要想完全明白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中你可以认为一个方法的引用变量有一个指向方法的指针,同时也有一个隐藏的指针指向闭包。我就不再举其他的例子了,能简单明了的让大家理解闭包的原理就够了。

详解JavaScript闭包的更多相关文章

  1. 【javascript】详解javascript闭包 — 大家准备好瓜子,我要开始讲故事啦~~

    前言: 在这篇文章里,我将对那些在各种有关闭包的资料中频繁出现,但却又千篇一律,且暧昧模糊得让人难以理解的表述,做一次自己的解读.或者说是对“红宝书”的<函数表达式/闭包>的那一章节所写的 ...

  2. js对象详解(JavaScript对象深度剖析,深度理解js对象)

    js对象详解(JavaScript对象深度剖析,深度理解js对象) 这算是酝酿很久的一篇文章了. JavaScript作为一个基于对象(没有类的概念)的语言,从入门到精通到放弃一直会被对象这个问题围绕 ...

  3. 详解javascript中的this对象

    详解javascript中的this对象 前言 Javascript是一门基于对象的动态语言,也就是说,所有东西都是对象,一个很典型的例子就是函数也被视为普通的对象.Javascript可以通过一定的 ...

  4. 详解JavaScript调用栈、尾递归和手动优化

    调用栈(Call Stack) 调用栈(Call Stack)是一个基本的计算机概念,这里引入一个概念:栈帧. 栈帧是指为一个函数调用单独分配的那部分栈空间. 当运行的程序从当前函数调用另外一个函数时 ...

  5. 详解javascript的类

    前言 生活有度,人生添寿. 原文地址:详解javascript的类 博主博客地址:Damonare的个人博客 Javascript从当初的一个"弹窗语言",一步步发展成为现在前后端 ...

  6. 详解Javascript的继承实现(二)

    上文<详解Javascript的继承实现>介绍了一个通用的继承库,基于该库,可以快速构建带继承关系和静态成员的javascript类,好使用也好理解,额外的好处是,如果所有类都用这种库来构 ...

  7. 【转】详解JavaScript中的this

    ref:http://blog.jobbole.com/39305/ 来源:foocoder 详解JavaScript中的this JavaScript中的this总是让人迷惑,应该是js众所周知的坑 ...

  8. 详解 javascript中offsetleft属性的用法(转)

    详解 javascript中offsetleft属性的用法 转载  2015-11-11   投稿:mrr    我要评论 本章节通过代码实例介绍一下offsetleft属性的用法,需要的朋友可以做一 ...

  9. 详解JavaScript的任务、微任务、队列以及代码执行顺序

    摘要: 理解JS的执行顺序. 作者:前端小智 原文:详解JavaScript的任务.微任务.队列以及代码执行顺序 思考下面 JavaScript 代码: console.log("scrip ...

随机推荐

  1. 我的java信息

    Java的运行环境版本: 1.7.0_07Java的运行环境供应商: Oracle CorporationJava供应商的URL: http://java.oracle.com/Java的安装路径:  ...

  2. centos7.0之Lnmp和Lamp

    首先配置防火墙 CentOS 7.0默认使用的是firewall作为防火墙 1.关闭firewall: systemctl stop firewalld.service #停止firewall sys ...

  3. iOS 之 Property List

    1. 概念 用于存储串行化对象,xml格式,存储到plist文件中. 2. 用途 存储用户设置. 3. 优点 程序运行时可动态创建和读写. 4. 使用说明 4.1. 获取plist文件 NSStrin ...

  4. Eclipse中应用的调试

    作为编程人员,程序的调试是一项基本功.在不使用IDE的时候,程序的调试多数是通过日志或者输入语句(System.out.println)的方式.可以把程序运行的轨迹或者程序运行过程中的状态显示给用户, ...

  5. Spring AOP切面的时候参数的传递

    Spring AOP切面的时候参数的传递 Xml: <?xml version="1.0" encoding="UTF-8"?> <beans ...

  6. Java泛型类型擦除导致的类型转换问题

    初步结论:泛型类型转换不靠谱: 源码: package com.srie.testjava; public class TestClassDefine4<T> { public stati ...

  7. Bootstrap入门(八)组件2:下拉菜单

    Bootstrap入门(八)组件2:下拉菜单   先引入本地的CSS文件和JS文件(注:1.bootstrap是需要jQuery支持的.2.需要在<body>当中添加) <link ...

  8. promise/bluebird源码

    本作品采用知识共享署名 4.0 国际许可协议进行许可.转载保留声明头部与原文链接https://luzeshu.com/blog/bluebirdsource 本博客同步在http://www.cnb ...

  9. oracle数据库包package小例子

    为了把某一个模块的函数.存储过程等方便查询维护,可以把它们打到一个包里.下面给出一个简单的小例子. 1.创建包头 create or replace package chen_pack is func ...

  10. Ubuntu14.04 安装Oracle JDK

    在Ubuntu 14.04 中安装 Oracle JDK6,7 或 8. 准备:添加add-apt-repository工具 #apt-get install python-software-prop ...