javascript 闭包浅析

来源:互联网 发布:nob2b 邮件群发软件 编辑:程序博客网 时间:2024/06/14 08:25

每个函数对象在声明或用表达式定义后都会被赋给一个特殊的内部属性,这个属性无法在代码中访问,但可以在浏览器调试中查看。例如在Chrome的调试界面在WatchExpressions中打印函数对象后,会看到一个<function scope>属性:

这个<functionscope>属性就是函数参考作用域链,是一个链表。头结点"可能"是声明或定义这个函数的函数的活动对象。所谓活动像是指一个函数执行时创建的其内部局部变量,参数等函数体内"一切"的一个集合。链表的下一节"可能"就是再外面那个函数的活动对象。作用域链的底部"总会"有一个Global对象,一般就是window对象。

 

前面有一些名词打上了引号,因为要对此补充说明。虽然函数式一个嵌套一个的,但最里面的函数的作用域链并不一定包含外层函数所有的活动对象。只有这个函数内部出现了对外部某个函数活动对象内变量的访问,才会在它的作用域链里添加这个外部函数的活动对象。而且,这个活动对象也并不包含对应的外部函数内部的所有变量,只包含内部函数访问到的变量。但是,无论是否访问Global对象的变量,Global对象是始终被包含在作用域链底部的。下面这个例子说明这一点:

打印func3函数时看到,作用域链里只包含func1函数的活动对象,且只出现了v1变量。底部仍出现了Global对象。

 

<function scope>属性总是包含该函数的外部函数创建的活动对象,当该函数被调用时,就会创建该函数本身的活动对象。这时,一个[[Scope]]属性就会被创建,内容也是一个链表,只不过该函数本身的活动对象被插在链表的顶部,链表其余部分就是<function scope>的内容。[[Scope]]就是函数调用作用域链,函数体内所有变量的访问都是在这个[[Scope]]内查找的。这也是为什么前面把<function scope>称为参考作用域链的原因。注意,一个函数每次调用时都会创建一个新的活动对象。

 

但在外部函数内部定义的所有内部函数体内,若有引用外部函数变量,则引用到的变量是同一个变量,因为所有内部函数的<function scope>作用域链里都保留外部函数的同一个活动对象的引用,所以引用到这个活动对象里的变量亦是同一个。要认识到,作用域链里的一切都是指针。下面是一个例子:

 

funcGetfuncAdd函数的作用域链中都包含指向funcOuter函数的同一个活动对象的指针。理解这一点后也就理解了下面这个例子,这是个闭包的错误用法:

function User(properties) {            for (var i in properties) {                this[ "get" + i ] = function () {                    return properties[i];                };            }        }        var user = new User({            name: "Bob",            age: 44        });        alert(user.getname()); //44        alert(user.getage()); //44

User这个构造函数将传入的参数里的属性名增加前缀get,并作为构造出的实例的属性,返回参数里对应的值。但两个get函数都返回44,因为这两个get函数的<function scop>里都引用到同一个User的活动对象,而在调用alert时这个活动对象里的变量i的值总是age(for循环后的最终值)。要解决这一问题,可采用如下方法,实际上是在<funciton scope>里增加了一环活动对象,而这一环的活动对象在每次循环创建时都是不同的:

        function User(properties) {            for (var i in properties) {                (function() {                    var j = i;                    this[ "get" + j ] = function () {                        return properties[j];                    };                }).apply(this);            }        }

我们将循环体用一个匿名函数包裹,这样一来,两个get函数的参考作用域链里分别包含两个匿名函数不同的活动对象,这两个活动对象里的变量j一个是name,一个是age。这个解决方法有两点需要留意,一个是var j=i;这一行,一开始我没加这一行,也试过var i=i;,发现都不行,所以若要延长作用域链,得将变量改名。还有一点是apply(this),一开始我没加,以为这个匿名函数的执行环境是User构造函数创建的实例,实际上发现是window对象,

所以要注意自执行匿名函数的执行环境都是window。

 

下面是些闭包的用途:

静态私有变量:

  

单例模式:

new Application()返回的对象随不同,但访问的资源都是components

 

 

 

 

原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 高中上不下去了怎么办 高三坚持不下去怎么办 word点了不保存怎么办 做了ppt没保存怎么办 中班安全教案迷眼了怎么办 美的空调尘满怎么办 高考报名系统密码忘记怎么办 高考理综8题怎么办 高三了语文很差怎么办 高三了语文成绩差怎么办 供太岁初一忘了怎么办 高一英语100多分怎么办 高一孩子英语差怎么办 高考中题目有错别字怎么办 相亲简单自我介绍后不回我怎么办 初中毕业没考上高中怎么办 幼儿园小朋友经常说脏话幼师怎么办 我不想当组长了怎么办 领导让我做组长怎么办 情人抓住把柄敲诈自己老公怎么办 我太看重朋友了怎么办 初中生下面长硬胡子痒怎么办 孩子不爱与人沟通怎么办 初一初二没学好初三怎么办 打印机提示存储已满怎么办 苹果6内存满了怎么办 手机总显示存储空间不足怎么办 我爱她她不爱我怎么办 孩子爱发脾气·父母怎么办 落枕怎么办简单快速的有效方法 老板评奖时偏把我落下怎么办 手机home键坏了怎么办 庙里求的葫芦丢了怎么办 判了抚养费不给怎么办 百度账号密码忘了怎么办 百度云会员到期后文件怎么办 百度网盘存储空间不足怎么办 网赌一天输14万怎么办 在部队训练伤了怎么办 cdrx6激活时不能继续了怎么办 大学毕业一年后找不到工作怎么办