作用域与闭包,js插件内部传递function()内部值

合集下载

javascript语言中函数闭包现象

javascript语言中函数闭包现象

浅析javascript语言中的函数闭包现象摘要:闭包在很多javascript高级应用中都会出现。

本文主要以javascript语言为例分析闭包现象的形成,理解闭包的运行机制及使用。

关键词:闭包;内部变量;作用域中图分类号:tp312.2 文献标识码:a 文章编号:1007-9599 (2012) 23-0000-02闭包问题是英格兰brighton beers活动中提出来的。

闭包的概念很抽象,如果不用代码来说明,将很难用描述性语句把它解释清楚。

所以本文将以javascript语言为例解释说明什么是闭包,分析闭包的运行机制及使用注意事项。

1 闭包的概念什么是闭包?在计算机科学中,闭包(closure)是词法闭包(lexical closure)的简称,是引用了自由变量的函数。

这个被引用的自由变量将和这个函数一同存在,即使已经离开了创造它的环境也不例外。

ecmascript允许使用内部函数--即函数定义和函数表达式位于另一个函数的函数体内。

[1]而且,这些内部函数可以访问它们所在的外部函数中声明的所有局部变量、参数和声明的其他内部函数。

当其中一个这样的内部函数在包含它们的外部函数之外被调用时,就会形成闭包。

所以,有另一种说法认为闭包是由函数和与其相关的引用环境组合而成的实体。

由于在javascript语言中,只有函数内部的子函数才能读取局部变量,因此可以把闭包简单理解成“定义在一个函数内部的函数”。

2 理解闭包在javascript中的运行及使用2.1 如何理解闭包闭包的创建相对容易,有时创建闭包编程人员根本没有意识到这是闭包,尤其是在ie等常见的浏览器环境下运行下,所编写的程序在很大程度上存在潜在的问题。

因此在编写javascript高级应用程序是,对闭包的使用和它的运行机制必须有一定了解。

而了解闭包运行机制的就要先解析在编写过程中的环境变量及作用域。

javascript中每个函数都是一个函数对象(函数实例),既然是对象,就有相关的属性和方法。

javascript中(function{})()写法解析

javascript中(function{})()写法解析

javascript中(function{})()写法解析javascript中(function{})()写法解析javascript 中(function{})()这种写法什么意思?最近在整理javascript 学习,发现这个问题了,在网上发现这么个解释最清楚最明白;(function(){})()相当于先定义 function xx(){},后调用 xx();()是最高优先级的,所以先执行function(){},这个定义了一个匿名函数,等于xx=function(){}接着就是调用xx()了;给个例子JScript codefunctionf1(a){ alert(a);functionf2(a){ returnfunction(){ alert(a); }}这里的var x=f2 就等于把函数传递给了f2,然后要执行这个函数,就必须加() 也就是x();也就是f2()还是(function f2(a){return function(){alert(a);另外还有一个问题就是命名空间的问题YY = YY||{};---声明一个叫YY的命名空间(定义一个全局的变量)(function() {ng=function() {------声明一个叫ng的命名空间(通过全局变量的增加属性的方式把闭包里的对象传到全局变量中,实现代码封装的效果)isUndefined: function(o) {return typeof o === 'undefined';isString: function(o) {return typeof o === 'string';---调用方法alert(ng.isString('test me'));这时候就有人不明了,楼上为什么要加(function() { 和)(); 最外面的这两行,有什么用啊?JScript codeYY=YY||{}; //---声明一个叫YY的'命名空间(定义一个全局的变量)function() { ng=function() {//------声明一个叫ng的命名空间(通过全局变量的增加属性的方式把闭包里的对象传到全局变量中,实现代码封装的效果)isUndefined:function(o) {returntypeofo==='undefined'; }, isString:function(o) {returntypeofo==='string'; } }; }//---调用方法alert(ng.isString('test me'));疑问在这:注释掉这两行有什么不一样的呢?不就是申明吗,为什么要用()()执行一下啊?答:(function(){})()意思是立即执行前一个括号里的function,相当于是一个匿名函数;由于里面的代码的执行,定义了ng这个对象,所以可以执行alert(ng.isString('test me'));调用isString方法。

js闭包原理使用场景

js闭包原理使用场景

闭包的基本原理在理解闭包的原理之前,我们先来了解一下JavaScript中的作用域和作用域链。

作用域作用域是指变量和函数的可访问范围。

在JavaScript中,有全局作用域和局部作用域。

全局作用域中定义的变量和函数可以在任何地方被访问到,而局部作用域中定义的变量和函数只能在其所在的作用域内被访问到。

作用域链作用域链是指变量和函数的查找路径。

在JavaScript中,每个函数都有一个作用域链,用于查找变量和函数的定义。

当一个函数被调用时,JavaScript引擎会创建一个称为执行上下文的内部对象,其中包含了该函数的所有局部变量、参数和内部函数。

作用域链的构建是在函数定义时确定的,而不是在函数调用时确定的。

闭包的定义闭包是指一个函数能够访问并操作其外部函数的变量,即使外部函数已经执行完毕。

简单来说,闭包就是能够读取其他函数内部变量的函数。

闭包的实现原理为了理解闭包的实现原理,我们需要了解JavaScript中的变量生命周期和垃圾回收机制。

在JavaScript中,当一个函数执行完毕后,其内部的局部变量通常会被销毁,释放内存。

但是,如果一个内部函数在外部函数执行完毕后还被引用,那么这个内部函数就会形成一个闭包,其内部的局部变量不会被销毁,仍然可以被访问和操作。

闭包的实现原理可以简单概括为以下几个步骤:1.当一个函数执行时,会创建一个执行上下文,并将其添加到执行上下文栈中。

2.在创建执行上下文时,会同时创建一个作用域链,用于变量和函数的查找。

3.当执行到一个函数内部定义的函数时,会创建一个闭包,并将其添加到作用域链中。

4.当外部函数执行完毕后,其执行上下文会被销毁,但闭包仍然存在于作用域链中,可以继续访问和操作外部函数的变量。

闭包的使用场景闭包在JavaScript中有着广泛的应用,以下是一些常见的使用场景:1.封装私有变量闭包可以用于创建私有变量,避免全局命名空间的污染。

通过在外部函数内部定义一个变量,并在内部函数中访问和操作该变量,可以实现私有变量的封装。

js比较难理解的知识点 知乎

js比较难理解的知识点 知乎

js比较难理解的知识点知乎以js比较难理解的知识点JavaScript作为一门非常灵活和强大的编程语言,有一些概念和知识点对于初学者来说可能会比较难以理解。

本文将介绍一些常见的js知识点,帮助读者更好地理解和掌握这门语言。

1. 闭包(Closures)闭包是JavaScript中非常重要但也容易令人迷惑的概念之一。

简单来说,闭包是指一个函数能够访问并操作其外部函数的变量,即使外部函数已经执行完毕。

这是由于JavaScript的作用域链机制,函数在创建时会保存对其外部作用域的引用。

闭包的使用可以带来很多好处,但也容易导致内存泄漏和性能问题,因此需要谨慎使用。

2. 原型链(Prototype chain)原型链是JavaScript实现继承的一种机制。

每个对象都有一个原型对象,而原型对象又有自己的原型对象,形成一个链式结构。

当访问一个对象的属性或方法时,如果该对象自身没有定义,则会沿着原型链向上查找。

这种机制可以实现属性和方法的继承,但也容易导致混乱和不可预测的行为。

3. 异步编程(Asynchronous programming)JavaScript是一门单线程的语言,但通过异步编程可以实现非阻塞的操作,提高程序的性能和响应能力。

异步编程的方式有很多,包括回调函数、Promise、Generator和async/await等。

这些概念和技术需要理解其工作原理和使用方式,以便编写高效的异步代码。

4. 作用域(Scope)作用域是指变量和函数的可访问范围。

JavaScript采用的是词法作用域,即变量的作用域在代码编写时就确定了。

在函数内部可以访问函数外部的变量,但函数外部不能访问函数内部的变量。

此外,JavaScript还有全局作用域和块级作用域等概念,需要理解其作用和使用方式。

5. this关键字this关键字是一个非常复杂和容易引起困惑的概念。

它的值取决于函数的调用方式,而不是函数的定义位置。

在全局作用域中,this 指向全局对象(浏览器中是window对象),而在函数内部,this 的值可能会有所不同。

详细图解作用域链与闭包

详细图解作用域链与闭包

详细图解作⽤域链与闭包因此本⽂的⽬的就在于,能够清晰明了得把闭包说清楚。

⼀、作⽤域与作⽤域链在详细讲解作⽤域链之前,我默认你已经⼤概明⽩了JavaScript中的下⾯这些重要概念。

这些概念将会⾮常有帮助。

基础数据类型与引⽤数据类型内存空间垃圾回收机制执⾏上下⽂变量对象与活动对象作⽤域在JavaScript中,我们可以将作⽤域定义为⼀套规则,这套规则⽤来管理引擎如何在当前作⽤域以及嵌套的⼦作⽤域中根据标识符名称进⾏变量查找。

这⾥的标识符,指的是变量名或者函数名JavaScript中只有全局作⽤域与函数作⽤域(因为eval我们平时开发中⼏乎不会⽤到它,这⾥不讨论)。

作⽤域与执⾏上下⽂是完全不同的两个概念。

我知道很多⼈会混淆他们,但是⼀定要仔细区分。

JavaScript代码的整个执⾏过程,分为两个阶段,代码编译阶段与代码执⾏阶段。

编译阶段由编译器完成,将代码翻译成可执⾏代码,这个阶段作⽤域规则会确定。

执⾏阶段由引擎完成,主要任务是执⾏可执⾏代码,执⾏上下⽂在这个阶段创建。

作⽤域链⽣命周期,如下图。

执⾏上下⽂⽣命周期我们发现,作⽤域链是在执⾏上下⽂的创建阶段⽣成的。

这个就奇怪了。

上⾯我们刚刚说作⽤域在编译阶段确定规则,可是为什么作⽤域链却在执⾏阶段确定呢?之所有有这个疑问,是因为⼤家对作⽤域和作⽤域链有⼀个误解。

我们上⾯说了,作⽤域是⼀套规则,那么作⽤域链是什么呢?是这套规则的具体实现。

所以这就是作⽤域与作⽤域链的关系,相信⼤家都应该明⽩了吧。

我们知道函数在调⽤激活时,会开始创建对应的执⾏上下⽂,在执⾏上下⽂⽣成的过程中,变量对象,作⽤域链,以及this的值会分别被确定。

之前⼀篇⽂章我们详细说明了变量对象,⽽这⾥,我们将详细说明作⽤域链。

作⽤域链,是由当前环境与上层环境的⼀系列变量对象组成,它保证了当前执⾏环境对符合访问权限的变量和函数的有序访问。

为了帮助⼤家理解作⽤域链,我我们先结合⼀个例⼦,以及相应的图⽰来说明。

Js闭包——精选推荐

Js闭包——精选推荐

Js闭包函数和对其周围状态(lexical environment,词法环境)的引⽤捆绑在⼀起构成闭包(closure)。

也就是说,闭包可以让你从内部函数访问外部函数作⽤域。

在 JavaScript 中,每当函数被创建,就会在函数⽣成时⽣成闭包。

词法作⽤域请看下⾯的代码:function init() {var name = "Mozilla"; // name 是⼀个被 init 创建的局部变量function displayName() { // displayName() 是内部函数,⼀个闭包alert(name); // 使⽤了⽗函数中声明的变量}displayName();}init();init()创建了⼀个局部变量name和⼀个名为displayName()的函数。

displayName()是定义在init()⾥的内部函数,并且仅在init()函数体内可⽤。

请注意,displayName()没有⾃⼰的局部变量。

然⽽,因为它可以访问到外部函数的变量,所以displayName()可以使⽤⽗函数init()中声明的变量name。

使⽤运⾏该代码后发现,displayName()函数内的alert()语句成功显⽰出了变量name的值(该变量在其⽗函数中声明)。

这个词法作⽤域的例⼦描述了分析器如何在函数嵌套的情况下解析变量名。

词法(lexical)⼀词指的是,词法作⽤域根据源代码中声明变量的位置来确定该变量在何处可⽤。

嵌套函数可访问声明于它们外部作⽤域的变量。

闭包现在来考虑以下例⼦:function makeFunc() {var name = "Mozilla";function displayName() {alert(name);}return displayName;}var myFunc = makeFunc();myFunc();运⾏这段代码的效果和之前init()函数的⽰例完全⼀样。

前端面试常见知识点

前端面试常见知识点

前端⾯试常见知识点1、JavaScript this指针、闭包、作⽤域this:指向调⽤上下⽂闭包:内部函数可以访问它们所在的外部函数中声明的所有局部变量、参数和声明的其他内部函数。

当其中⼀个这样的内部函数在包含它们的外部函数之外被调⽤时,就会形成闭包。

闭包的好处:(1)不增加额外的全局变量,(2)执⾏过程中所有变量都是在匿名函数内部。

闭包的缺点:(1)滥⽤闭包函数会造成内存泄露,因为闭包中引⽤到的包裹函数中定义的变量都永远不会被释放,内存消耗很⼤,所以不能滥⽤闭包,否则会造成⽹页的性能问题,在IE中可能导致内存泄露。

解决⽅法是,在必要的时候,及时释放这个闭包函数,(在退出函数之前,将不使⽤的局部变量全部删除。

)(2)闭包会在⽗函数外部,改变⽗函数内部变量的值。

所以,如果你把⽗函数当作对象(object)使⽤,把闭包当作它的公⽤⽅法(Public Method),把内部变量当作它的私有属性(private value),这时⼀定要⼩⼼,不要随便改变⽗函数内部变量的值。

作⽤域:作⽤域就是变量与函数的可访问范围,即作⽤域控制着变量与函数的可见性和⽣命周期。

在JavaScript中,变量的作⽤域有全局作⽤域和局部作⽤域两种。

全局作⽤域:在代码中任何地⽅都能访问到的对象拥有全局作⽤域(1)最外层函数和在最外层函数外⾯定义的变量拥有全局作⽤域(2)所有末定义直接赋值的变量⾃动声明为拥有全局作⽤域(3)所有window对象的属性拥有全局作⽤域局部作⽤域(Local Scope) :和全局作⽤域相反,局部作⽤域⼀般只在固定的代码⽚段内可访问到,最常见的例如函数内部,所有在⼀些地⽅也会看到有⼈把这种作⽤域称为函数作⽤域,2. Javascript作⽤域链?理解变量和函数的访问范围和⽣命周期,全局作⽤域与局部作⽤域的区别,JavaScript中没有块作⽤域,函数的嵌套形成不同层次的作⽤域,嵌套的层次形成链式形式,通过作⽤域链查找属性的规则需要深⼊理解。

js中function()使用方法

js中function()使用方法

js中function()使⽤⽅法javascript 函数不同于其他的语⾔,每个函数都是作为⼀个对象被维护和运⾏的。

通过函数对象的性质,可以很⽅便的将⼀个函数赋值给⼀个变量或者将函数作为参数传递。

在继续讲述之前,先看⼀下函数的使⽤语法:以下是引⽤⽚段:function func1(…){…}var func2=function(…){…};var func3=function func4(…){…};var func5=new Function();复制代码代码如下:<script type="text/javascript">// 1, ⽅法调⽤模式// 当⼀个函数被保存为对象的⼀个属性时,我们称之它为该对象的⼀个⽅法,那么this被绑定到该对象上var myObject={name : "myObject" ,value : 0 ,increment : function(num){this.value += typeof(num) === 'number' ? num : 0;return this;} ,toString : function(){return '[Object:' + + ' {value:' + this.value + '}]';}}alert(myObject.increment(10).increment(20).toString()); // [Object:myObject {value:30}]// 2, 函数调⽤模式// 当⼀个函数并⾮⼀个对象的函数时,那么它被当作⼀个函数来调⽤,this被绑定到全局对象上。

这是语⾔设计的⼀个错误。

倘若语⾔设计正确,当内部函数调⽤时,this应该仍然绑定到外部函数的this变量上var myObject={name : "myObject" ,value : 0 ,increment : function(num){this.value += typeof(num) === 'number' ? num : 0;return this;} ,toString : function(){return '[Object:' + + ' {value:' + this.value + '}]';},getInfo: function(){var self=this;return (function(){//return this.toString(); // 内部匿名函数中this指向了全局对象window,输出 [object Window]return self.toString(); // 定义⼀个变量selft并给它赋值为this,那么内部函数通过该变量访问到指向该对象的this})();}}alert(myObject.increment(10).increment(20).toString()); // [Object:myObject {value:30}]// 3, 构造器调⽤模式// JavaScript是⼀门基于原型继承的语⾔, 这意味着对象可以直接从其他对象继承属性, 该语⾔是⽆类别的。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

《作用域与闭包:this,var,(function () {})》目标无具体目标知识点1.理解js 中var 的作用域2.了解闭包的概念3.理解this 的指向课程内容*es6中新增了let 关键词,与块级作用域,相关知识参考:/#docs/let *var 作用域先来看个简单的例子:var parent=function () {var name ="parent_name";var age =13;var child=function () {var name ="child_name";var childAge =0.3;// => child_name 13 0.3console.log(name, age, childAge);};child();// will throw Error// ReferenceError: childAge is not definedconsole.log(name, age, childAge);};parent();直觉地,内部函数可以访问外部函数的变量,外部不能访问内部函数的变量。

上面的例子中内部函数child 可以访问变量age,而外部函数parent 不可以访问child 中的变量childAge,因此会抛出没有定义变量的异常。

有个重要的事,如果忘记var,那么变量就被声明为全局变量了。

function foo() {value ="hello";}foo();console.log(value); // 输出hello console.log(global.value) // 输出hello这个例子可以很正常的输出hello,是因为value变量在定义时,没有使用var关键词,所以被定义成了全局变量。

在Node 中,全局变量会被定义在global对象下;在浏览器中,全局变量会被定义在window对象下。

如果你确实要定义一个全局变量的话,请显示地定义在global或者window对象上。

这类不小心定义全局变量的问题可以被jshint 检测出来,如果你使用sublime 编辑器的话,记得装一个SublimeLinter插件,这是插件支持多语言的语法错误检测,js 的检测是原生支持的。

JavaScript 中,变量的局部作用域是函数级别的。

不同于C 语言,在C 语言中,作用域是块级别的。

JavaScript 中没有块级作用域。

js 中,函数中声明的变量在整个函数中都有定义。

比如如下代码段,变量i 和value 虽然是在for 循环代码块中被定义,但在代码块外仍可以访问i 和value。

function foo() {for (var i =0; i <10; i++) {var value ="hello world";}console.log(i); //输出10console.log(value);//输出hello world}foo();所以有种说法是:应该提前声明函数中需要用到的变量,即,在函数体的顶部声明可能用到的变量,这样就可以避免出现一些奇奇怪怪怪的bug。

但我个人不喜欢遵守这一点,一般都是现用现声明的。

这类错误的检测交给jshint 来做就好了。

闭包闭包这个概念,在函数式编程里很常见,简单的说,就是使内部函数可以访问定义在外部函数中的变量。

假如我们要实现一系列的函数:add10,add20,它们的定义是int add10(int n)。

为此我们构造了一个名为adder 的构造器,如下:var adder=function (x) {var base = x;returnfunction (n) {return n + base;};};var add10 =adder(10);console.log(add10(5));var add20 =adder(20);console.log(add20(5));每次调用adder 时,adder 都会返回一个函数给我们。

我们传给adder 的值,会保存在一个名为base 的变量中。

由于返回的函数在其中引用了base 的值,于是base 的引用计数被+1。

当返回函数不被垃圾回收时,则base 也会一直存在。

我暂时想不出什么实用的例子来,如果想深入理解这块,可以看看这篇/articles/6731.html闭包的一个坑for (var i =0; i <5; i++) {setTimeout(function () {console.log(i);}, 5);}上面这个代码块会打印五个5出来,而我们预想的结果是打印0 1 2 3 4。

之所以会这样,是因为setTimeout 中的i 是对外层i 的引用。

当setTimeout 的代码被解释的时候,运行时只是记录了i 的引用,而不是值。

而当setTimeout 被触发时,五个setTimeout 中的i 同时被取值,由于它们都指向了外层的同一个i,而那个i 的值在迭代完成时为5,所以打印了五次5。

为了得到我们预想的结果,我们可以把i 赋值成一个局部的变量,从而摆脱外层迭代的影响。

for (var i =0; i <5; i++) {(function (idx) {setTimeout(function () {console.log(idx);}, 5);})(i);}this在函数执行时,this 总是指向调用该函数的对象。

要判断this 的指向,其实就是判断this 所在的函数属于谁。

在《javaScript语言精粹》这本书中,把this 出现的场景分为四类,简单的说就是:∙有对象就指向调用对象∙没调用对象就指向全局对象∙用new构造就指向新对象∙通过apply 或call 或bind 来改变this 的所指。

1)函数有所属对象时:指向所属对象函数有所属对象时,通常通过.表达式调用,这时this自然指向所属对象。

比如下面的例子:var myObject = {value:100};myObject.getValue=function () {console.log(this.value); // 输出 100// 输出 { value: 100, getValue: [Function] },// 其实就是 myObject 对象本身console.log(this);return this.value;};console.log(myObject.getValue()); // => 100getValue()属于对象myObject,并由myOjbect进行.调用,因此this指向对象myObject。

2) 函数没有所属对象:指向全局对象var myObject = {value:100};myObject.getValue=function () {var foo=function () {console.log(this.value) // => undefinedconsole.log(this);// 输出全局对象 global};foo();return this.value;};console.log(myObject.getValue()); // => 100在上述代码块中,foo函数虽然定义在getValue的函数体内,但实际上它既不属于getValue也不属于myObject。

foo并没有被绑定在任何对象上,所以当调用时,它的this指针指向了全局对象global。

据说这是个设计错误。

3)构造器中的this:指向新对象js 中,我们通过new关键词来调用构造函数,此时this 会绑定在该新对象上。

var SomeClass=function(){this.value=100;}var myCreate =new SomeClass();console.log(myCreate.value); // 输出100顺便说一句,在js 中,构造函数、普通函数、对象方法、闭包,这四者没有明确界线。

界线都在人的心中。

4) apply 和call 调用以及bind 绑定:指向绑定的对象apply() 方法接受两个参数第一个是函数运行的作用域,另外一个是一个参数数组(arguments)。

call() 方法第一个参数的意义与apply() 方法相同,只是其他的参数需要一个个列举出来。

简单来说,call 的方式更接近我们平时调用函数,而apply 需要我们传递Array 形式的数组给它。

它们是可以互相转换的。

var myObject = {value:100};var foo=function(){console.log(this);};foo(); // 全局变量 global foo.apply(myObject); // { value:100 }foo.call(myObject); // { value: 100 }var newFoo = foo.bind(myObject);newFoo(); // { value: 100 }完。

相关文档
最新文档