理解Javascript_15_作用域分配与变量访问规则,再送个闭包


Posted in Javascript onOctober 20, 2010

作用域分配与变量访问规则

在 ECMAScript 中,函数也是对象。函数对象在变量实例化过程中会根据函数声明来创建,或者是在计算函数表达式或调用 Function 构造函数时创建。(关于'函数对象'请见《理解Javascript_08_函数对象》)。每个函数对象都有一个内部的 [[scope]] 属性,这个属性也由对象列表(链)组成。这个内部的[[scope]] 属性引用的就是创建它们的执行环境的作用域链,同时,当前执行环境的活动对象被添加到该对象列表的顶部。当我们在函数内部访问变量时,其实就是在作用域链上寻找变量的过程。

理论性太强了(总结死我了!),还是让我们来看一段代码吧:

<script type="text/javascript"> 
function outer(){ 
var i = 10; 
function inner(){ 
var j = 100; 
alert(j);//100 
alert(i);//10 
alert(adf); 
} 
inner(); 
} 
outer(); 
</script>

下图清晰的展现了上述代码的内存分配与作用域分配情况:
理解Javascript_15_作用域分配与变量访问规则,再送个闭包
下面来解释一下:
1.载入代码,创建全局执行环境,此时会在可变对象(window)中添加outer变量,其指向于函数对象outer,此时作用域链中只有window对象.
2.执行代码,当程序执行到outer()时,会在全局对象中寻找outer变量,成功调用。
3.创建outer的执行环境,此时会新创建一个活动对象,添加变量i,设置值为10,添加变量inner,指向于函数对象inner.并将活动对象压入作用域链中.并将函数对象outer的[[scope]]属性指向活动对象outer。此时作用域链为outer的活动对象+window.
4.执行代码,为 i 成功赋值。当程序执行到inner()时,会在函数对象outer的[[scope]]中寻找inner变量。找到后成功调用。
5.创建inner的执行环境,新建一个活动对象,添加变量j,赋值为100,并将该活动对象压入作用域链中,并函数对象inner的[[scope]]属性指向活动对象inner.此时作用域链为:inner的活动对象+outer的活动对象+全局对象.
6.执行代码为j赋值,当访问i、j时成功在作用域中找到对应的值并输出,而当访问变量adf时,没有在作用域中寻找到,访问出错。

注:通过内存图,我们会发现作用域链与prototype链是如此的相象。这说明了很多问题...(仁者见仁智者见智,自己探寻答案吧!)

闭包原理
在我们了解了作用域的问题之后,对于闭包这个问题已经很简单了。什么是闭包?闭包就是封闭了外部函数作用域中变量的内部函数。
我们来看一个典型的闭包运用:生成increment值

<script type="text/javascript"> 
var increment = (function(){ 
var id = 0; 
return function(){ 
return ++id; 
} 
})() 
alert(increment());//1 
alert(increment());//2 
</script>

外层匿名函数返回的是一个内嵌函数,内嵌函数使用了外层匿名函数的局部变量id。照理外层匿名函数的局部变量在返回时就超出了作用域因此increment()调用无法使用才对。这就是闭包Closure,即函数调用返回了一个内嵌函数,而内嵌函数引用了外部函数的局部变量、参数等这些应当被关闭(Close)了的资源。这是怎么一回事呢?让我们来寻找答案:
理解Javascript_15_作用域分配与变量访问规则,再送个闭包
根据Scope Chain的理解可以解释,返回的内嵌函数已经持有了构造它时的Scope Chain,虽然outer返回导致这些对象超出了作用域、生存期范围,但JavaScript使用自动垃圾回收来释放对象内存: 按照规则定期检查,对象没有任何引用才被释放。因此上面的代码能够正确运行。

参考:
http://www.cnblogs.com/RicCC/archive/2008/02/15/JavaScript-Object-Model-Execution-Model.html
http://www.cn-cuckoo.com/2007/08/01/understand-javascript-closures-72.html

Javascript 相关文章推荐
Javascript 获取链接(url)参数的方法[正则与截取字符串]
Feb 09 Javascript
IE6浏览器中window.location.href无效的解决方法
Nov 20 Javascript
jquery中获取元素里某一特定子元素的代码
Dec 02 Javascript
javascript基础语法——全面理解变量和标识符
Jun 02 Javascript
实现微信小程序的wxml文件和wxss文件在webstrom的支持
Jun 12 Javascript
JS点击缩略图整屏居中放大图片效果
Jul 04 Javascript
解决js相同的正则多次调用test()返回的值却不同的问题
Oct 10 Javascript
使用ECharts实现状态区间图
Oct 25 Javascript
JS使用队列对数组排列,基数排序算法示例
Mar 02 Javascript
使用konva和vue-konva库实现拖拽滑块验证功能
Apr 27 Javascript
在实例中重学JavaScript事件循环
Dec 03 Javascript
微信小程序中使用vant框架的具体步骤
Feb 18 Javascript
理解Javascript_14_函数形式参数与arguments
Oct 20 #Javascript
理解Javascript_13_执行模型详解
Oct 20 #Javascript
用jquery与css打造个性化的单选框和复选框
Oct 20 #Javascript
Jquery插件之多图片异步上传
Oct 20 #Javascript
jquery判断checkbox(复选框)是否被选中的代码
Oct 20 #Javascript
jQuery下扩展插件和拓展函数的写法(匿名函数使用的典型例子)
Oct 20 #Javascript
JQuery 拾色器插件发布-jquery.icolor.js
Oct 20 #Javascript
You might like
PHP 危险函数解释 分析
2009/04/22 PHP
PHP下使用mysqli的函数连接mysql出现warning: mysqli::real_connect(): (hy000/1040): ...
2016/02/14 PHP
基于thinkPHP类的插入数据库操作功能示例
2017/01/06 PHP
php array_map()函数实例用法
2021/03/03 PHP
Javascript客户端将指定区域导出到Word、Excel的代码
2008/10/22 Javascript
javascript读取xml实现javascript分页
2013/12/13 Javascript
jquery动态添加删除(tr/td)
2015/02/09 Javascript
详谈javascript中DOM的基本属性
2015/02/26 Javascript
jQuery插件开发的五种形态小结
2015/03/04 Javascript
jquery用ajax方式从后台获取json数据后如何将内容填充到下拉列表
2015/08/26 Javascript
seajs加载jquery时提示$ is not a function该怎么解决
2015/10/23 Javascript
JavaScript在网页中画圆的函数arc使用方法
2015/11/13 Javascript
JS函数arguments数组获得实际传参数个数的实现方法
2016/05/28 Javascript
AngularJS基础 ng-keydown 指令简单示例
2016/08/02 Javascript
jQuery实现可拖拽的许愿墙效果【附demo源码下载】
2016/09/14 Javascript
jQuery实现弹幕效果
2017/02/17 Javascript
详解VueJS 数据驱动和依赖追踪分析
2017/07/26 Javascript
Webpack优化配置缩小文件搜索范围
2017/12/25 Javascript
vue项目tween方法实现返回顶部的示例代码
2018/03/02 Javascript
vue模块拖拽实现示例代码
2019/03/09 Javascript
详解如何理解vue的key属性
2019/04/14 Javascript
Vue中错误图片的处理的实现代码
2019/11/07 Javascript
微信域名检测接口调用演示步骤(含PHP、Python)
2019/12/08 Javascript
JavaScript实现栈结构Stack过程详解
2020/03/07 Javascript
微信小程序实现搜索框功能及踩过的坑
2020/06/19 Javascript
快速了解Vue父子组件传值以及父调子方法、子调父方法
2020/07/15 Javascript
[05:14]辉夜杯主赛事第二日 RECAP精彩回顾
2015/12/27 DOTA
python 回调函数和回调方法的实现分析
2016/03/23 Python
聊聊Python中的pypy
2018/01/12 Python
python2.7实现FTP文件下载功能
2018/04/15 Python
HTML5 Canvas 破碎重组的视频特效的示例代码
2019/09/24 HTML / CSS
公司前台辞职报告
2014/01/19 职场文书
2014年教学工作总结
2014/11/13 职场文书
安全保证书格式
2015/02/28 职场文书
班主任远程培训研修日志
2015/11/13 职场文书
css position fixed 左右双定位的实现代码
2021/04/29 HTML / CSS