要想完全明白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. JS 弹出层 定位至屏幕居中

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...

  2. SVN和Git的一些用法总结

    (A)SVN (1)查看日志提交的时候一般会写上注释,如果要查看提交日志,用以下命令: 1 svn log -l 4 其中,-l 4表示只查看最近4条日志(也可以没有这样的参数,就表示查看所有日志). ...

  3. python 自动化运维项目_目录

    微信小程序监控界面 CMDB 跳板机 代码上线系统 网站用户访问质量监测 分布式监控 Docker自动化管理平台 Openstack二次开发

  4. js原生设计模式——9外观模式封装

    1.事件处理程序兼容性封装 <!DOCTYPE html><html lang="en"><head>    <meta charset= ...

  5. 推荐系统中的Graph Model

    转自:http://www.cnblogs.com/wentingtu/archive/2012/05/28/2521166.html 推荐中对graph model的研究主要有两个方面,一个是如何构 ...

  6. ThinkPHP 模板的包含、渲染、继承

    一.模板包含        <include file="完整模板文件名" />        <include file="./Tpl/default ...

  7. linux学习笔记----权限与命令之间的关系(极重要)

    一.权限与命令之间的关系 二.文件与目录的默认权限与隐藏权限 1)umask为默认的权限(通过umask -S)查看你的系统的默认权限. umask的分数是指该默认值需要减掉的权限,比如说umask= ...

  8. javascript 简单工厂

    function detail() { this.imgArr = []; this.codeArr = []; } detail.prototype.addimg = function(img) { ...

  9. Bootstrap Paginator分页插件+ajax 实现动态无刷新分页

    之前做分页想过做淘宝的那个,但是因为是后台要求不高,就Bootstrap Paginator插件感觉还蛮容易上手,所以就选了它. Bootstrap Paginator分页插件下载地址: Downlo ...

  10. loadrunner controller:集合点策略

    集合点只有在多用户并发运行的时候才能体现它的作用. Scenario ---> Rendezvous 打开集合点设置界面,如下图所示: 我们可以看到Vusers 列表框里有两个用户,这与我们设置 ...