研究过js的朋友大多会说,理解了js的原型和闭包就可以了,然后又说这些都是js的高级内容,然后就又扯到了各种神马的作用域。。。然后不少

人就会被忽悠的云里雾里。。。下面我也试着来说说闭包,看我说的这个是否浅显易懂。。。

一:闭包含义

  闭包是个专业词汇,这样才能显得在js中是高大上的货色,官方定义我这里就不敢修改它,定义如下:就是有权访问另一个函数作用域的变量的函数。

二:一个简单的场景

  上面的定义大概也能看得懂,但是不知道为什么不把“另一个函数” 改成 “包含函数”,因为我觉得“包含函数”可能更通俗易懂些,光有定义还不行,我

还得找个经典的例子看一看。

     <script type="text/javascript">

         //比较函数
function createComparison(propertyName) { return function (obj1, obj2) {
var item1 = obj1[propertyName];
var item2 = obj2[propertyName]; if (item1 < item2)
return -; if (item1 > item2)
return ; if (item1 == item2)
return ;
}
} //比较name
var compare = createComparison("name"); var result = compare({ name: "d", age: }, { name: "c", age: });
</script>

这是一个说闭包原理的经典例子,经典在哪里?如例子中我使用compare时,我的function是可以访问到createComparison函数中的

propertyName字段的,其实这个理解并不复杂,我们去看看浏览器的scope variables就一清二楚了。

我们可以清楚的看到,在chrome的本地变量表中清楚的记录着当前执行函数中的本地变量列表,并且还进行了分类,比如上面的”局部函数变量(Local)“,

”包含函数变量(Closure)”,“全局变量(Global)”,那下面有个有趣的问题就来了,chrome怎么知道我代码执行到20行的时候,当前的local variables有

哪些呢?而且还能给我分门别类,是不是太奇葩了????但是仔细推敲一下就能豁然开朗,肯定有一个变量保存着当前的variables,不然的话,chrome

去哪读取呢?对不对????????

三:解开谜底

  其实在每个function里面都有一个scope属性,当然这个属性被引擎屏蔽了,你是看不见也摸不着的,它里面就保存着当前函数的 local variables,如

果应用到上面demo的话,就是全局函数中有一个scope,createComparison有一个scope,匿名的compare有一个scope,而且这三个scope还是通过

链表链接的,画个简图如下:

从上面简图中可以看到,其实整个函数中有三个scope,每个scope都是用next指针链接,这样就形成了一个链表,当我执行下面代码的时候

 var result = compare({ name: "d", age:  }, { name: "c", age:  });

js引擎会拿到当前compare的scope,通过scope属性的next指针,就可以区分哪些变量属于哪个函数,这样你就看到了chrome对variables

的分门别类了。

四:对一个案例的加深理解

  我想读到这里,你应该明白了闭包的原理,其实没什么稀奇的,就是一个读取scope属性的问题。只是被装逼成高大上了,下面看段代码:

     <script type="text/javascript">

         var arr = new Array();

         function Person() {
for (var i = ; i < ; i++) { //要记住,这个属性函数申明,只有立即执行才会取scope属性
var item = function () {
return i;
}; arr.push(item);
}
} Person(); for (var i = ; i < arr.length; i++) {
console.log(arr[i]());
}
</script>

在这个例子中,我想做一个function()数组的array,并且最后都能输出各自的值(1,2,3,4,5...10),但是结果又是怎样呢?可以看到下图中输出

的其实是10个10。。。这样就违背了我的原始意图。

上面这个陷阱的最大问题在于你自以为我在匿名function中写了return i;就认为它是属于匿名函数的,其实这就大错特错了,因为这个i就算走到天涯

海角都不属于匿名函数,而是属于它的包含函数Person,所以原理应该是这样,比如你看,当我执行arr[0]()的时候,这时候匿名函数就会通过scope

去找i,但是在匿名函数的scope中没有i,所以就通过next找到了Person函数,确实在Person中找到了i,但是这个时候i已经是10了,然后结束scope

查找输出10。解决方案也很简单,给每个匿名function一个副本就好了,具体原理我想你应该可以用scope推测出来了,对不对。

Javascript之旅——第十站:为什么都说闭包难理解呢?的更多相关文章

  1. Javascript之旅——第十一站:原型也不好理解?

    写到这篇,我的js系列也快接近尾声了,所以这个系列不会遗留js来实现面向对象的核心——原型,有些人说原型不好理解,其实嘛,要想系统 的理解原型,最便捷的方式就是看看经典的书,少看些博客,博客这东西只是 ...

  2. Javascript之旅——第八站:说说instanceof踩了一个坑

    前些天写js遇到了一个instanceof的坑,我们的页面中有一个iframe,我在index页面中计算得到了一个array,然后需要传递到Flight页面 这个嵌套的iframe中的一个函数(Sea ...

  3. Javascript之旅——第七站:说说js的调试

    最近比较吐槽,大家都知道,现在web前端相对几年前来说已经变得很重了,各种js框架,各种面对对象,而且项目多了,就会提取公共模块, 这些模块的UI展示都一样,不一样的就是后台逻辑,举个例子吧,我们做企 ...

  4. Javascript之旅——第四站:parseInt中要注意的坑

    前些天信用卡站点要接入一个新功能,不过还真比较坑爹,asp站点,大家都知道信用卡的背面是有一个有效期的,在对接银行中这个信息 一定是要传给银行做数据校验,用户在语音输入信用卡有效期后,系统会做一个有效 ...

  5. Sql Server之旅——第十站 看看DML操作对索引的影响

    我们都知道建索引是需要谨慎的,当只有利大于弊的时候才适合建,我们也知道建索引是需要维护成本的,这个维护也就在于DML操作了, 下面我们具体看看到底DML对索引都有哪些内幕.... 一:delete操作 ...

  6. Sql Server之旅——第七站 为什么都说状态少的字段不能建索引

    我们在学sqlserver的时候,大多教科书和前辈们都说状态少的字段不要建索引,由此带来的开销还不如不建索引,但是这句话有多少人真的知道, 或者说有多少人真的对此有比较深刻的理解,而不是听别人道听途说 ...

  7. Javascript之旅——第六站:看看writable特性

    说起js中的那些特性标记,总觉得有些怪怪的,那为什么要说到这个attribute,起源于对一个问题的疑问,我们都知道window对象其实就是 浏览器窗口的一个实例,既然是一个实例,那这个实例就应该有“ ...

  8. Javascript之旅——第五站:说说那些所谓的包装类型

    最近不看犀牛书了,那本翻译的特烂而且好拗口,尤其是原型那块说的乱七八糟,后来经同事介绍,买了本js高级程序设计,然后就继续 苦逼的看,不吐槽了,继续说说js中有新鲜感的包装类型. 一:String 说 ...

  9. Javascript之旅——第三站:几个需要注意的运算符

    平时写惯了C#,所以会觉得什么样的运算符就应该做什么样的运算,但是有一天你的习惯被其他语言颠覆了,不知道是不是有一股强大的好奇 心,刚好在js中,我的这种习惯就被颠覆了,下面就看看哪些运算符颠覆了我的 ...

随机推荐

  1. Note: This element neither has attached source nor attached Javadoc and hence no Javadoc could be found.

    在Eclipse中开发Android项目时,鼠标停放在想要查看帮助文档的类上面,发现没有显示帮助文档,显示了下面一句话: Note: This element neither has attached ...

  2. IOS 2D游戏开发框架 SpriteKit

    最近发现Xcode自带的2D游戏开发框架SpriteKit可以直接引入到APP中进行混合开发,这就是说可以开发出既带业务应用又带游戏的苹果APP,咋怎么觉得这是一个自己的小发现....呵呵....., ...

  3. python2.x 默认编码问题

    python2.x中处理中文,是一件头疼的事情.网上写这方面的文章,测次不齐,而且都会有点错误,所以在这里打算自己总结一篇文章. 我也会在以后学习中,不断的修改此篇博客. 这里假设读者已有与编码相关的 ...

  4. C++11 之 nullptr

    C++11 中,nullptr 是空指针,可用来给 (指向任意对象类型的) 指针赋值 广义整型 (integral types) = char, short, int, long, long long ...

  5. MAC使用CocoaPods

    前言,還是那句話,按照濤叔下面畫黃色的步驟順序執行就好了 使用CocoaPods兩種方式:使用之前安裝的插件&命令行. 一.利用插件 1.創建項目后添加CocoaPods 2.在文本框中輸入如 ...

  6. 理解 OpenStack 高可用(HA) (4): Pacemaker 和 OpenStack Resource Agent (RA)

    本系列会分析OpenStack 的高可用性(HA)概念和解决方案: (1)OpenStack 高可用方案概述 (2)Neutron L3 Agent HA - VRRP (虚拟路由冗余协议) (3)N ...

  7. mac下彻底卸载mysql方法

    sudo rm /usr/local/mysqlsudo rm -rf /usr/local/mysql*sudo rm -rf /Library/StartupItems/MySQLCOMsudo ...

  8. jQuery Transit 过渡效果

    jQuery Transit 使用 CSS3 的新特性来实现过渡效果,比默认的.animate方法要顺畅得多. 因为使用 CSS3 进行过渡效果,所以对不支持 CSS3 的浏览器效果有所下降. 语法和 ...

  9. Slick – 这是你需要的最后一款 jQuery 传送带插件

    slick 是一款完全响应式的 jQuery 传送带插件,能够根据容器自动适应宽度.在现代浏览器中会使用 CSS3 来实现特殊效果,可以使用扩展方法对项目进行添加.删除和过滤.这是你需要的最后一款 j ...

  10. Node异步

    一 Node异步工作原理 Node.js 异步编程的直接体现就是回调,回调函数在完成任务后就会被调用,Node 使用了大量的回调函数,Node 所有 API 都支持回调函数. 二 同步代码示例 先建立 ...