作用域链与闭包
作用域链【主要作用:变量名解析】
如果你理解了作用域链,那么闭包对于你而言,理解起来就相当地简单了。
作用域链,可以看成是一个有序检索的对象列表。
【有序检索:即就近原则“由近及远”,全局对象始终是最后一个】
举例来说,也就是:
如果js的最*代码(不包含在函数内的代码),它的作用域链——一个全局对象;
如果js代码中有函数,但是没嵌套,它的作用域链有两个对象,第一个是函数内的变量即函数参数,第二个就是全局对象【第一第二的顺序很重要】;
如果有函数嵌套,那么作用域链至少有3个对象。
【作用域链的创建规则】
定义函数的时候,会保存一个作用域链;
调用函数的时候,有两个操作:一是将函数内的局部变量保存在一个新建对象中,然后添加到函数定义时的作用域链中;二是会创建一个“运行期上下文”的内部对象,每一个运行期上下文都有一个单独的作用域链,而调用时会将上面提到那个作用域链中的对象相当于复制一份到运行期上下文这个作用域链中。
在嵌套函数时,有些不一样,我们每一次调用外部函数的时候,内部函数都需要重新定义一次,因为每次运行外部函数时,它的作用域链都是不相同的。内部函数在每次定义时也有微妙的差别——在每次调用外部函数的时候,内部函数的代码是相同的,而且关联这段代码的作用域链也不相同。
1 function buttoninit(){ 2 for(var i=1;i<4;i++){ 3 var b=document.getelementbyid("button"+i); 4 b.addeventlistener("click",function(){ 5 alert("button"+i); },false); 6 } 7 } 8 window.onload=buttoninit; 9 //--结果:都是button4 10 11 12 13 function buttoninit(){ 14 for(var i=1;i<4;i++){ 15 (function a(j) { 16 console.log(j); 17 var b=document.getelementbyid("button"+j); 18 b.addeventlistener("click",function(){ 19 alert("button"+j); 20 },false); 21 })(i) 22 } 23 } 24 window.onload=buttoninit; 25 //--结果:button1、button2、button3
闭包:【主要作用:变量私有化】
缺点:
1、 闭包会让函数内部变量始终保存在内存中,需要手动释放资源;
【解决办法:即将函数设置为null】
2、过多的闭包导致内存泄漏。
实现闭包:
当嵌套函数被作为外部函数的返回值返回或者存储在某处的属性里,这时会有一个外部引用指向这个嵌套函数,就不会被回收,并且这个嵌套函数所指向的变量绑定对象也不会回收。
var name = 'one'; function a() { var name = 'two'; function f() { return name; } return f; } a()();
function counter(m) { return{ get count(){ return m++; }, set count(n){ if(m<=n) m=n; else throw error('count can only be set to a larger value'); } }; } var c = counter(100); console.log(c.count);//--100 console.log(c.count);//--101 c.count = 200; console.log(c.count);//--200 console.log(c.count=200);//--throw error console.log(c.count=300);//--300
上一篇: 换个口味