函数,作用域链,执行环境,闭包

越是关系混乱的东西越要混在一起来说,把混乱的关系处理好了,我们就可以利用它们的关系建立起强大的知识网络 :)

当一个函数被创建时,会包含一个[[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。

posted @ 2013-05-23 10:32  danyan  阅读(172)  评论(0)    收藏  举报