手机版

javascript深入理解射流研究…闭包

时间:2021-10-22 来源:互联网 编辑:宝哥软件园 浏览:

一、变量的作用域要理解闭包,首先要了解Javascript的特殊变量作用域。变量的范围无非就是两种:全局变量和局部变量。Javascript语言的特殊之处在于可以直接从函数内部读取全局变量。代码Js var n=999函数f1(){ alert(n);} f1();//999另一方面,在函数外读取函数内部的局部变量自然是不可能的。代码Js函数f1(){ var n=999;} alert(n);//错误这里有一点需要注意。在函数内部声明变量时,必须使用var命令。如果没有,你实际上声明了一个全局变量!代码Js函数f1(){ n=999;} f1();警报(n);//999 - .出于各种原因,我们有时需要在函数中获取局部变量。但是,如前所述,在正常情况下,这是不可能的,只能通过替代方法来实现。也就是说,在函数内部,定义另一个函数。代码Js函数f1(){ n=999;函数F2(){ alert(n);//999}}在上面的代码中,函数f2包含在函数f1中,f1中的所有局部变量对f2都是可见的。但是反过来,f2内部的局部变量对f1是不可见的。这是Javascript语言特有的“链作用域”结构,其中子对象会逐级查找所有父对象的变量。因此,父对象的所有变量对于子对象都是可见的,否则就不是真的。既然f2可以读取f1中的局部变量,那么只要取f2作为返回值,我们就可以在f1之外读取它的内部变量!代码Js函数f1(){ n=999;函数F2(){ alert(n);}返回F2;}var结果=f1();结果();//999 - .各种专业文献中对“闭包”的定义非常抽象,难以理解。我的理解是闭包是可以读取其他函数内部变量的函数。在Javascript语言中,只有函数内部的子函数可以读取局部变量,所以闭包可以简单理解为“函数内部定义的函数”。因此,本质上,闭包是连接函数内部和外部的桥梁。- .它最大的用处有两个,一个是可以读取上面提到的函数内部的变量,另一个是可以将这些变量的值一直保存在内存中。这句话怎么理解?请看下面的代码。代码Js函数f1(){ var n=999;nAdd=function(){ n=1 } function F2(){ alert(n);}返回F2;}var结果=f1();结果();//999 NadD();结果();//1000在这段代码中,结果实际上是闭包f2函数。一共运行了两次,第一次的值是999,第二次的值是1000。这证明函数f1中的局部变量n始终存储在内存中,并且在f1调用后不会自动清除。为什么会这样?原因是f1是f2的父函数,f2赋给了一个全局变量,导致f2总是在内存中,而f2的存在依赖于f1,所以f1总是在内存中,调用后不会被垃圾回收回收。这段代码中另一个值得注意的点是行“nAdd=function(){n=1}”。首先,在nAdd之前没有使用var关键字,所以nAdd是全局变量,不是局部变量。其次,nAdd的值是匿名函数,而匿名函数本身是闭包,所以nAdd相当于一个setter,可以对函数内部和函数外部的局部变量进行操作。

- .解决方法是在退出函数之前删除所有未使用的局部变量。2)闭包将在父函数之外,并改变父函数内部变量的值。因此,如果将父函数用作对象,将闭包用作其公共方法,将内部变量用作其私有值,则必须注意不要随意更改父函数的内部变量的值。- .代码Js变量名称=“窗口”;var object={ name : 'My Object ',getname func : function(){ return function(){ return this . name;};}};alert(object . GetNameFunc());//窗户-。函数innerFun(){ a;警报(a);innerFun()上面的代码错误。innerfun()的作用域在outfun()内部,在outfun()外部调用是错误的。将其改为如下,即闭包: Js代码函数outfun(){ var a=0;函数innerFun(){ a;警报(a);}返回innerFun//注意这里} var obj=ExterFun();obj();//结果是1 obj();//结果是2var obj 2=ExterFun();obj 2();//结果是1 obj 2();//结果是2。什么是闭包:当内部函数在定义它的范围之外被引用时,就创建了内部函数的闭包。如果内部函数引用位于外部函数中的变量,则这些变量在调用外部函数后不会在内存中释放。因为闭包需要它们......................警报(a);} var a=4;outfun();警报(a);结果是0,4。因为var关键字是在函数内部使用的,用来维护一个内部outFun()的范围。看看下面的代码: Js代码函数outfun(){//no var a=0;警报(a);} var a=4;outfun();警报(a);奇怪的是结果是0,0。为什么呢?范围链是一个描述路径的术语,沿着这个路径可以确定变量值。当执行a=0时,由于没有使用var关键字,赋值操作将遵循作用域链到var a=4;并更改其值。-如果您不太理解javascript闭包,请阅读以下转载文章:(:http://www.felixwoo.com/archives/247转载)1。什么是结束?官方的解释是闭包是一个表达式(通常是一个函数),有很多变量和这些变量绑定的环境,所以这些变量也是表达式的一部分。我相信很少有人能直接理解这句话,因为他的描述太学术了。其实这句话是:JavaScript中的所有函数都是一个闭包。一般来说,嵌套函数产生的闭包更强大,大部分时候就是我们所说的“闭包”。请看下面的代码:函数a(){ var I=0;函数b(){ alert(I);}返回b;} var c=a();c();这个代码有两个特点:1。函数B嵌套在函数A内部;2.函数a返回函数b,引用关系如下:

这样,执行var c=a()后,变量c实际指向函数b,执行c()后,会弹出一个窗口,显示I(第一次为1)的值。这段代码实际上创建了一个闭包。为什么呢?因为函数A外部的变量C引用函数A内部的函数B,也就是当函数A内部的函数B被函数A外部的变量引用时,就创建了闭包。让我们说得更透彻些。所谓“闭包”,就是在构造函数体中定义另一个函数作为目标对象的方法函数,这个对象的方法函数反过来引用外部函数体中的临时变量。这使得可以间接维护原始构造函数使用的临时变量值,只要目标对象可以在其生存期内始终保持其方法。虽然初始构造函数调用已经结束,临时变量的名称已经消失,但是变量的值始终可以在目标对象的方法中引用,并且该值只能由该方法访问。即使再次调用同一个构造函数,也只会生成新的对象和方法,新的临时变量只对应新的值,与上次调用的值无关。二、闭包的作用是什么?简单来说,闭包的作用就是在A完成执行并返回后,闭包使得Javascript的垃圾收集机制GC不回收A占用的资源,因为A的内部函数B的执行依赖于A中的变量,这是对闭包的作用非常直白的描述,不专业也不精确,但很可能就是这个意思。理解闭包需要一个渐进的过程。在上面的例子中,由于闭包的存在,函数a返回后我总是存在于a中,所以每次执行c()时,我都是alert加1后的值。让我们想象另一种情况。如果A不返回函数B,情况就完全不同了。因为A执行后,B不返回A的外部世界,只被A引用,此时A只会被B使用,所以函数A和B相互引用,不受外部世界的干扰(被外部世界引用),函数A和B会被GC回收。(后面会详细介绍Javascript的垃圾收集机制。)三、闭包中的微观世界如果我们想更多地了解闭包以及函数A和嵌套函数B之间的关系,我们需要引入其他几个概念:函数执行上下文、调用对象、作用域和作用域链。以函数A从定义到执行的过程为例来说明这些概念。定义函数A时,js解释器会将函数A的作用域链设置为定义A时A所在的“环境”,如果A是全局函数,则作用域链中只有一个窗口对象。当函数a被执行时,a将进入相应的执行上下文。在创建执行环境的过程中,首先给A增加一个作用域属性,即A的作用域,其值在步骤1中为作用域链。也就是a.scope=a的范围链.然后,执行环境创建一个调用对象。活动也是一个带有属性的对象,但是它没有原型,不能通过JavaScript代码直接访问。创建活动对象后,将活动对象添加到A的范围链的顶部。此时,的范围链包含两个对象:的活动对象和窗口对象。下一步是在活动对象上添加一个arguments属性,保存调用函数A时传递的参数,最后将函数A的所有形式参数和函数B的内部引用都添加到A的活动对象中,这一步完成了函数B的定义,所以和第三步一样,将函数B的作用域链设置到B定义的环境中,也就是A的作用域中,此时就完成了整个函数A从定义到执行的步骤。此时a返回函数b对c的引用,函数b的作用域链包含函数a的活动对象的引用,这意味着b可以访问a中定义的所有变量和函数.函数b被c引用,依赖于函数a,所以函数a返回后不会被GC回收。当执行函数b时,它将与上述步骤相同。因此,b的范围链包含三个对象:b的活动对象、a的活动对象和窗口对象,如下图所示:

如图,在函数B中访问一个变量时,搜索顺序是:先搜索自己的活动对象,如果存在,返回,如果不存在,继续搜索函数A的活动对象,依次搜索,直到找到为止。如果函数b中有原型对象,在找到自己的活动对象后找到自己的原型对象,然后继续寻找。这是Javascript中的变量搜索机制。如果在整个范围链中找不到它,它将返回undefined。总之,这一段提到了两个重要的词:函数的定义和执行。在本文中,函数的范围是在定义函数时确定的,而不是在执行函数时确定的(参见步骤1和3)。用一段代码解释这个问题:函数f(x){ var g=function(){ return x;}返回g;} var h=f(1);警报(h());这段代码中的变量h指向f中的匿名函数(由g返回)。假设函数h的作用域是通过执行alert(h())确定的,那么h的作用域链就是:h的活动对象-alert-the-window对象的活动对象。假设函数h的作用域是在定义的时候确定的,也就是说h所指向的匿名函数在定义的时候已经确定了它的作用域。在执行的时候,h的作用域链是:h的活动对象-f的活动对象-窗口对象。如果第一个假设成立,则输出值未定义;如果第二个假设成立,输出值为1。结果证明第二个假设是正确的,这意味着函数的范围是在定义函数时确定的。第四,闭包的应用场景保护函数中变量的安全。以初始例子为例,函数A中的I只能被函数B访问,而不能被其他手段访问,从而保护了I的安全性,在内存中维护一个变量。和前面的例子一样,因为闭包的原因,函数A中的I总是存在于内存中,所以每次执行C()时,我都会被加1。通过保护变量的安全性来实现JS私有属性和私有方法(不能从外部访问)。私有属性和方法在构造函数之外不可访问。函数构造函数(.){ var=this;var membername=value函数成员名(.) {.}}以上三点是闭包最基本的应用场景,很多经典案例都源于此。五、Javascript的垃圾收集机制在Javascript中,如果一个对象不再被引用,就会被GC收集。如果两个对象相互引用,并且不再被第三个引用,那么这两个相互引用的对象也将被回收。因为函数A被B引用,而B在A之外被C引用,这就是函数A执行后不会被回收的原因。不及物动词结论理解JavaScript的闭包是高级JS程序员的必由之路。只有了解它的解释和运行机制,才能写出更安全、更优雅的代码。

版权声明:javascript深入理解射流研究…闭包是由宝哥软件园云端程序自动收集整理而来。如果本文侵犯了你的权益,请联系本站底部QQ或者邮箱删除。