基于Javascript闭包的基础共享
如果我们对诸如独立对象的范围和函数等基本概念有了更好的理解,我们就很容易理解闭包的概念,并将它应用到实际编程实践中。在处理DOM事件方面,大多数程序员自己已经使用闭包而不知道它,在这种情况下,嵌入Javascript引擎bug的浏览器可能会导致内存泄漏这个问题,是程序员调试也常常混淆。
用简单的语句来描述关闭Javascript的概念:由于Javascript的函数对象,对象是一组属性和属性值,并可以对象,然后定义的函数,在函数如果函数func成为理所当然,在函数内部声明,然后外部调用内部函数,这个过程已经关闭。 U3000 U3000
封闭性:
让我们看一个例子。如果你不理解Javascript的特性,很难找到原因:
复制代码代码如下所示:
无功外= { };
功能clousetest(){
var数组
对于(var i = 0;i < array.length;i++){
变量x { };
x.no =我;
x.text =数组{我};
x.invoke =函数(){
印刷(I);
}
Outter.push(X);
}
}
调用这个函数
clousetest();
打印(外{ 0 }。调用());
打印(外{ 1 }。调用());
打印(外{ 2 }。调用());
打印(外{ 3 }。调用());
手术结果如何许多初学者可能会得到这个答案:
零
一
二
三
但是,运行此程序的结果是:
四
四
四
四
事实上,在每一次迭代,所以声明x.invoke =功能({打印)(我);}还没有执行,只有构建一个功能为打印(我);对象的功能,那就是当我= 4,迭代停止和外部函数返回。当外{ 0 }。调用()又称为,i的值仍然是4,所以调用在外部数组的每个元素返回i的值:4。如何解决这个问题呢我们可以声明一个匿名函数并立即执行它:
复制代码代码如下所示:
无功外= { };
功能clousetest2(){
var数组
对于(var i = 0;i < array.length;i++){
变量x { };
x.no =我;
x.text =数组{我};
x.invoke =功能(无){
返回函数(){
打印(否);
}
}(一);
Outter.push(X);
}
}
clousetest2();
在这个例子中,当我们将一个值分配给x.invoke,我们先运行一个函数,可以返回一个函数并立即执行,使x.invoke每个迭代器相当于执行一个语句。
复制代码代码如下所示:
0
x.invoke =函数(){打印(0);}
1
x.invoke =函数(){打印(1);}
2
x.invoke =函数(){打印(2);}
3
x.invoke =函数(){打印(3);}
因此,您可以得到正确的结果。闭包允许您引用外部函数中存在的变量。但是,它不是创建变量时创建的值,而是使用外部函数中变量的最后一个值。
闭包的使用:
现在,闭包的概念是明确的。让我们来看看闭包的用法,事实上,我们可以通过闭包来做很多事情,比如模拟面向对象的代码风格;更优雅、更简洁的代码表达;在某种程度上提高代码的效率。
缓存:
要看一个例子,假设我们有一个非常耗时的进程函数对象,每个调用将花费很长时间,所以我们需要在调用这个函数时计算被存储的值,首先在缓存中搜索,如果不是,计算,然后更新缓存和返回值,如果找到,可以直接找到返回值。
闭包之所以可以这样做,是因为它不释放外部引用,因此函数中的值可以保留。
复制代码代码如下所示:
Var CachedSearchBox =(函数(){()
var,
计数= };
返回{
attachsearchbox:功能(DSID){
如果(DSID缓存){ / /如果缓存中的结果
返回缓存{ DSID }; / /直接返回缓存中的对象
}
VaR fsb document.getelementbyid(DSID); / /新
缓存{ DSID } =外频; / /更新缓存
如果(count.length > 100){ / /保罗< = 100的缓存大小
删除缓存count.shift(){ };
}
返回FSB;
},
ClearSearchBox:功能(DSID){
如果(DSID缓存){
缓存{ DSID }。clearselection();
}
}
};
});
var obj1 = cachedsearchbox.attachsearchbox(input1 );
//alert (obj1);
var obj2 = cachedsearchbox.attachsearchbox(input1 );
实现封装:
复制代码代码如下所示:
var =函数(){()
作为内部和外部访问功能的变量范围
var;
返回{
getName:函数(){
返回的名称;
},
集名称:功能(新名称){
名称=新名称;
}
}
(});
打印(人名);直接访问,结果未定义。
Print (person.getName ());
person.setname(Jack);
打印(person.getname());
结果如下:
未定义
违约
杰克
闭包的另一个重要用途是在面向对象中实现对象。传统的对象语言为类提供模板机制,以便不同的对象(类的实例)具有独立的成员和状态,并且不互相干扰。虽然Javascript中没有这种机制,但是我们可以使用闭包来模拟这样的机制:
复制代码代码如下所示:
功能人(){
var;
返回{
getName:函数(){
返回的名称;
},
集名称:功能(新名称){
名称=新名称;
}
}
};
var =人();
打印(john.getname());
john.setname();
打印(john.getname());
Var Jack =人();
打印(jack.getname());
Jack.setName(Jack);
打印(jack.getname());
结果如下:
违约
约翰
违约
杰克
应注意Javascript闭包:
1。内存泄漏:
在不同的Javascript解释器的实现,由于在翻译本身的缺陷,闭包的使用可能会导致内存泄漏,内存泄漏是一个严重的问题,将严重影响浏览器的响应速度,降低用户体验,甚至导致浏览器无响应的现象。Javascript解释器有垃圾收集机制。一般来说,引用计数的形式被使用。如果一个对象的引用计数为零,垃圾收集机制将回收,这是自动的。然而,封闭的概念后,这个过程是比较复杂的,在关闭,因为局部变量可以用在未来的某个时间,这样的垃圾收集机制不应对这些外部引用局部变量,如果有循环引用对象的一个引用B,B参考C和C指的是,这种情况使得垃圾收集机制,引用计数不为零的结果,导致内存泄漏。
提及2。语境:
复制代码代码如下所示:
$(函数(){())
VaR对美元(div #面板);
this.id =内容;
Con.click(function(){()
警报(此ID);
});
});
这里引用的警报(id)的值是多少许多开发人员可能会根据闭包的概念做出错误的判断:
内容
原因是,this.id显示指定的内容,在点击回调,形成闭合将参考this.id,那么返回值的内容。但事实上,警报会弹出面板,原因是这样的,虽然闭包可以参考本地变量,但是涉及到这个时间,是有点微妙,因为调用对象的存在,所以,当关闭时(当面板单击事件),在这里本文指的是jQuery对象。在一个匿名函数this.id =内容是一个匿名函数本身的操作。两本参考的对象也不一样。
如果您想在事件处理函数中访问这个值,我们必须做一些更改:
复制代码代码如下所示:
$(函数(){())
VaR对美元(div #面板);
this.id =内容;
var =;
Con.click(function(){()
警报(自我id);
});
});
在这种方式中,我们认为指在事件处理函数的局部变量,外部的自我,不是这样的。这种技术在实际应用中具有多方面的应用,并讨论了在稍后的章节。关于关闭更多的内容将在第九章中详细讨论,包括其他的命令式语言关闭,关闭在实际项目中的应用,等等。
附:由于水平有限,难免有文字错误,或语言本身不合适,欢迎及时纠正,并提出建议。