函数,作用域链,执行环境,闭包
越是关系混乱的东西越要混在一起来说,把混乱的关系处理好了,我们就可以利用它们的关系建立起强大的知识网络 :)
当一个函数被创建时,会包含一个[[scope]]属性,指向这个函数的作用域链。作用域链里包含这个函数的父域,祖先域,当然也包括全局作用域。这些域其实都是包含变量的对象。
当一个函数被执行时,会为它创建一个执行环境,通过复制函数的[[scope]]属性中的对象构建起执行环境的作用域链,然后,这个函数的活动对象会被推入执行环境作用域链的最前端。构成了一个完整的执行环境作用域链。
当我们在函数中访问一个变量时,会从执行环境作用域链的最前端开始,逐级搜索,直到找到该变量。这也就引出了一个优化问题。
var apple=4; function eat(){ var banana=apple+3; var orange=apple+5; return apple+banana+orange; }
当我们在函数作用域中多次引用全局变量时,每一次,都会顺着函数执行环境作用域链向上搜索,直到找到apple变量,假如作用域链很长,或者引用次数很多,那么就存在性能问题,嘻嘻,说“性能问题”这四个字时很心虚,因为没有亲自去验证,嗯嗯,应该掌握一两个验证“性能问题”的方法。不过,可以明确的是,让浏览器做同样的事情(都是搜索作用域链)做得越多,损耗就越大,啦啦啦。
我们可以这样
var apple=4; function eat(){ var copyApple=apple; var banana=copyApple+3; var orange=copyApple+5; return copyApple+banana+orange; }
如此一来,我们仅在给copyApple赋值时需要搜索到全局作用域,其它时候,直接在函数的活动对象(也就是作用域链的最前端)就找到了apple的值(此时在copyApple中)。最大程度降低了搜索长度。
闭包就是函数,函数就是闭包。闭包本身没什么可讨论的。当我们保留着对一个函数的引用,而这个函数又引用着它的作用域链中的一个变量时,我们会特别地强调这个函数是一个闭包,即使它本来就是一个闭包。好吧,我们且看这个被我们称之为闭包的函数身上会发生哪些事。首先,因为有作用域链的存在,它无论在什么地方被调用,都能找到那个被它引用着的变量,倒也挺不错的,去郊游随身带个帐篷,挺好的。嘻嘻,昨天超哥发微博说触屏手机最大的问题就是触屏,然后有人回复说按键手机最大的问题也是按键,好吧,作用域链最大的问题也是作用域链。
function assignHandler(){ var element = document.getElementById('some'); element.onclick=function(){ alert(element.id); } }
因为匿名函数保存着对assignHandler函数活动对象的引用,所以对element元素的引用也一直被保存着,element元素将无法被浏览器销毁,什么内存泄露之类的。。。
解决办法
function assignHandler(){ var element=document.getElementById('some'); var id=element.id; element.onclick=function(){ alert(id); } element=null; }
通过把element设置为null,引用解除,因为我们只是想得到element的id,所以创建一个id变量,存放element的id。
浙公网安备 33010602011771号