javascript作用域和闭包

javascript采用的是词法作用域规则,没有块级作用域,都是以函数为单位,就是说,函数定义时的作用域链到函数执行时依然有效。全局变量在程序中始终都是有定义的,局部变量在声明它的函数体内以及其所嵌套的函数内始终是有定义的。

 

可以把局部变量看做是“自定义的属性”,它类似于你在全局添加一个变量,这个变量就会变成window对象的一个属性。那么你在函数内部添加一个变量,就可以认为,这个变量成了该函数【其实是“执行环境对象”】的一个属性,只不过不能直接用“函数名.变量”访问罢了。

 

javascript的工作过程分为两个步骤:编译和执行。


编译阶段:声明并初始化函数参数,参数会被赋值;声明局部变量,包括将匿名函数赋给一个局部变量,但并不初始化它们,就是说局部变量未被赋值;声明并初始化函数,但不执行。


执行阶段:给局部变量赋值,执行函数。

 

函数在定义(声明)时,会保存一个【作用域链】。当函数每次被调用时,都会产生一个“新的【执行环境对象】”,里面保存的是在函数中定义的局部变量。这个【执行环境对象】,会被添加到定义时保存的【作用域链】上面。函数执行完毕,返回的时候,就从【作用域链】上删除这个【执行环境对象】。如果不存在嵌套的函数,也没有其它引用指向这个【执行环境对象】,它就会被回收。也就是说,一旦函数执行完以后,里面的局部变量就不存在了。

 

当Javascript需要查找变量x的值的时候,就会从作用域链中的第一个对象开始查找,如果这个对象有一个名为x的属性,则直接使用这个属性的值,如果第一个对象中不存在名为x的属性,Javascript会查找作用域链上的下一个对象,依此类推,直到最顶层的全局对象(浏览器是window,NodeJs中是global),如果都没找到,会抛出一个引用错误异常(ReferenceError)。

闭包

但是,如果函数里面又定义了嵌套的函数,那么每个嵌套的函数都会有一个自己的【作用域链】,并且这个【作用域链】指向一个【执行环境对象】。如果嵌套的函数被作为返回值返回,或者存储在某处的属性里面,这时就会有一个外部引用指向这个嵌套的函数,它就不会被回收,它指向的【执行环境对象】也不会被回收。

 

闭包的核心理解:当一个函数返回一个址引用(对象、函数、数组、json)时,并且这个址引用使用了【执行环境对象】中的某些变量,那么就会创建一个对【执行环境对象】的引用,导致【执行环境对象】不能被回收,就形成了闭包。

 

闭包,由函数创建!一个函数,返回一个稍后执行的新函数或者对象(对象里有方法),而且这个新函数或方法,使用了原函数的参数或者原函数里面的某个变量,就会形成一个闭包。注意,函数中this和arguments不是变量。

 

例1:Ajax是异步执行的


function sendAjax(){

         vara=’jay’;

         $.Ajax({

                   success:function(){  console.log(a);  }

});

}

sendAjax();

原函数sendAjax执行时,会创建一个执行环境对象,里面包括变量a和匿名函数的声明,这个匿名函数被保存在一个名为success的属性上,它会在sendAjax执行完以后才执行,而且里面引用了执行环境对象中的变量a,所以当success函数执行的时候,虽然sendAjax已经执行完毕,但它创建的执行环境对象仍然存在,变量a仍然可以访问。

 

例2:循环和闭包


var buttons =document.getElementsByTagName(‘button’);

for(var i=0;i<buttons.length;i++){

         buttons[i].click= function(){

         console.log(i);

}

}

如果是上面的写法,虽然也有闭包,但是执行环境对象始终是一个,这样就导致i的值始终是最后一个,没有达到我们想要的效果。

for(var i=0;i<buttons.length;i++){

         (function(n){

         buttons[n].click = function(){

          console.log(n);

}

})(i);

}

我们采用了一个自执行函数来实现闭包效果,每次循环,都会创建一个新的执行环境对象,在这个对象里面,i的值就相当于局部变量了,不会再受外部影响。

我们也可以用下面这种写法,把闭包函数单独拿出来,每次调用show()也会创建一个新的执行环境对象。

for(var i=0;i<buttons.length;i++){

         buttons[i].click= show(i);

}

function show(n){

         returnfunction(){ console.log(n); }

}

 

Javascript中的垃圾自动回收机制,原理是引用计数。当一个实体没有人引用它的时候,就会被删除。像函数、数组、对象、json和null,都属于址引用,就是说,函数名称会保存在内,但函数体则保存在中。我们return function(){},其实是返回一个函数的地址,也就是我们常说的,变量保存的是函数的引用。我们把一个函数或对象,赋给一个变量,也只是把地址赋给它(即:创建一个引用)。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值