开发者社区> 吞吞吐吐的> 正文

详解JavaScript闭包

简介:
+关注继续查看

 要想完全明白JavaScript的闭包,要先明白js中的一些基础原理,然后我再给出一些例子来讲解闭包。

  在执行JavaScript时会创建一个执行环境(excution context),执行环境定义了变量或函数可以访问的其他数据。每个执行环境都有一个与之关联的变量对象(variable object 有些地方叫域对象(Scope object)),在执行环境中定义的所有变量和函数都保存在这个对象中。虽然我们编写的代码无法访问这个对象,但解析器在处理数据时会在后台使用它。

  全局执行环境是最外层的一个执行环境。根据js实现的宿主环境的不同,环境对象不一样。浏览器中,全局执行环境是window,node.js的全局变量是global,所有的全局变量和方法都保存在全局对象中。

  每个函数都有自己的执行环境。当调用进入一个函数时,函数的执行环境就会被创建。代码在执行环境中运行时,他创建用于保存变量对象的作用域链(scope chain)。他的作用是保存一个执行环境所有可以访问的变量或函数的有序集合。作用域的最前面是当前执行的代码所在执行环境的变量对象。如果当前的执行环境是一个函数,就将函数的活动对象作为变量对象,刚开始时只有一个变量arguments。作用域链中的下一个变量对象是包含当前环境变量的外部环境也就是他的调用者,再下一个是更外层的,至到全局执行环境。

  所以在一个执行中的方法内访问一个不存在于这个执行环境中的变量时不会报错,解析器会从作用域链的顶端的变量对象开始找,如果找不到就找下一个执行环境的变量对象,一直到全局环境变量。如果有则停止查找。如果找到全局变量对象还是没有发现,就会报错。

  简单说就是,一个函数体内就是一个执行环境,当一个函数在执行时,会创建一个作用链,这个链中有自己的变量对象,同时也有外层的变量对象。

  示例1:全局执行环境

var value1 =  1;
var value2 = 2;

 

  直接运行上面的代码,也就是说我们在一个全局执行环境中定义了两个变量,所以他俩会被保存在全局对象中这里用global保存。如下图所示

 

 

示例2.全局环境中的方法

复制代码
var value1 = 11;
var value2 = 22;

function log() {
    var logValue = "writing... ";
    console.log(logValue, "value1 :", value1, "  value2 ", value2);
}
log();
复制代码

 

  在log函数中,他的作用域链包含两个对象:一个是自己的的变量对象(包含arguments对象)和全局环境变量对象,所以在函数内访问value1和value2时就可以沿着作用域链找找他俩。

 

 示例3:闭包(嵌套函数 )

复制代码
var value1 = 11;
var value2 = 22;

function log() {
    var logValue = "writing... ";
    function nested() {
        console.log(logValue, "value1 :", value1, "  value2 ", value2);
    }
    return nested;
}
var fun1 = log();

fun1();
复制代码

 

  当你在一个函数内又创建了函数,那么就会创建闭包。当函数开始执行时闭包就会在堆上分配堆栈帧,而且在函数返回时不会被释放掉。在上面的代码中有三个执行环境一个是全局执行环境,一个是log()的局部执行环境,还有一个是nested()的执行环境。nested()可以访问log和global的变量.log()可以访问自己的global的变量:

  nested()函数从log()方法中被返回,他的作用域链被初始化为log()中定义的所有活动对象,和全局变量对象,这样nested()函数就可以访问所有的变量了。更重要的是log()执行完毕后,他的变量对象不会被销毁,因为nested()函数仍然在引用这个变量对象。也可以说,log()函数执行完后,log()的作用域链被销毁,但变量对象仍然保留在内存中,直到nested()销毁后,引用的log()的变量对象才会被销毁。

 

   有c++或c经验的程序员,可能会认为返回的是一个方法的指针,nested和fun1变量是两个指向这个方法的指针,其实不然,c++言语指向方法的指针和JavaScript中对一个方法的引用有很大的不同,JavaScript中你可以认为一个方法的引用变量有一个指向方法的指针,同时也有一个隐藏的指针指向闭包。我就不再举其他的例子了,能简单明了的让大家理解闭包的原理就够了。

 本文转自lpxxn博客园博客,原文链接:http://www.cnblogs.com/li-peng/p/6444317.html,如需转载请自行联系原作者


版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

相关文章
关于 JS 闭包看这一篇就够了
关于 JS 闭包看这一篇就够了
20 0
浏览器原理 09 # 作用域链和闭包 :代码中出现相同的变量,JavaScript引擎是如何选择的?
浏览器原理 09 # 作用域链和闭包 :代码中出现相同的变量,JavaScript引擎是如何选择的?
13 0
重学前端 18 # JavaScript的闭包和执行上下文
重学前端 18 # JavaScript的闭包和执行上下文
25 0
【JavaScript】40_函数闭包
# 15、函数 创建一个函数,第一次调用时打印1,第二次调用打印2,以此类推 可以利用函数,来隐藏不希望被外部访问到的变量 ## 闭包: 闭包就是能访问到外部函数作用域中变量的函数 什么时候使用: 当我们需要隐藏一些不希望被别人访问的内容时就可以使用闭包 构成闭包的要件: 1. 函数的嵌套 2. 内部函数要引用外部函数中的变量 3. 内部函数要作为返回值返回 ```html <script> // let num = 0 // function fn(){ // num++ /
6 0
js基础笔记学习159-闭包的一些注意事项2
js基础笔记学习159-闭包的一些注意事项2
16 0
js基础笔记学习158-闭包的一些注意事项1
js基础笔记学习158-闭包的一些注意事项1
15 0
js基础笔记学习156-闭包简介2
js基础笔记学习156-闭包简介2
7 0
js基础笔记学习157-闭包的原理1
js基础笔记学习157-闭包的原理1
17 0
js基础笔记学习155-闭包简介1
js基础笔记学习155-闭包简介1
20 0
JavaScript 闭包
JavaScript 闭包
23 0
文章
问答
文章排行榜
最热
最新
相关电子书
更多
Javascript中的函数
立即下载
Javascript异步编程
立即下载
JS零基础入门教程(上册)
立即下载