deeper understanding of closure in Javascript
我读了一个答案上的评论,看到了这个评论:
[the closure] doesn't persist the state of foo so much as creates a special scope containing (1) the returned function and (2) all the external variables referenced at the time of the return. This special scope is called a closure.
好的,到目前为止还不错。下面是我不知道的有趣的部分:
Case in point... if you had another var defined in foo that was not referenced in the return function, it would not exist in the closure scope.
我想这是有道理的,但除了记忆的使用/表现,这还有什么意义呢?
问题——如果范围中的所有变量都包含在闭包中,那么这会让我做些什么,而我不能用当前模型做这些呢?
我觉得你太直截了当了。注释只是说您不能在函数范围之外访问它(它不是公共访问的),而不是说它在函数中根本不可用。返回的函数将可以访问所有外部函数范围,无论是什么。如果内部函数不提供访问范围的方法,您就不能访问外部函数之外的范围。
例如,此表达式的计算结果为4:
1 2 3 4 5 6 7 8 9 10 11 | function testClosure(){ var x = 2; return function(y){ alert(eval(y)); } } var closure = testClosure(); closure("x+2"); //4 |
http://jsfiddle.net/dmrch/
因此,尽管没有直接引用,但
似乎Chrome和Firefox至少尝试过对此进行优化,因为如果您没有提供任何引用
http://jsfiddle.net/fgekx/1/
但这只是一个内存管理细节,而不是语言的相关属性。如果有任何可能的方法可以引用这个变量,它就会被传递,我怀疑其他浏览器可能不会以同样的方式优化这个变量。编码到规范总比实现好。在这种情况下,尽管规则实际上是:"如果您有任何可能的方法访问它,它将是可用的"。另外,不要使用eval,因为它确实会阻止代码优化任何东西。
if you had another var defined in foo that was not referenced in the return function, it would not exist in the closure scope.
这并不完全准确;变量是闭包范围的一部分,即使它可能不会直接在函数内部引用(通过查看函数代码)。区别在于引擎如何优化未使用的变量。
例如,当您使用DOM元素时,闭包范围中未使用的变量会导致内存泄漏(在某些引擎上)。以这个经典的例子为例:
1 2 3 4 5 6 | function addHandler() { var el = document.getElementById('el'); el.onclick = function() { this.style.backgroundColor = 'red'; } } |
来源
在上面的代码中,内存泄漏(至少在IE和Mozilla中),因为
另一方面,Chrome使用不同的垃圾收集器:
In V8, the object heap is segmented into two parts: new space where objects are created, and old space to which objects surviving a garbage collection cycle are promoted. If an object is moved in a garbage collection cycle, V8 updates all pointers to the object.
这也被称为世代或短暂的垃圾收集器。尽管更复杂,但这种类型的垃圾收集器可以更准确地确定是否使用变量。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 | Please have a look below code: for(var i=0; i< 5; i++){ setTimeout(function(){ console.log(i); },1000); } Here what will be output? 0,1,2,3,4 not that will be 5,5,5,5,5 because of closure So how it will solve? Answer is below: for(var i=0; i< 5; i++){ (function(j){ //using IIFE setTimeout(function(){ console.log(j); },1000); })(i); } Let me simple explain, when a function created nothing happen until it called so for loop in 1st code called 5 times but not called immediately so when it called i.e after 1 second and also this is asynchronous so before this for loop finished and store value 5 in var i and finally execute setTimeout function five time and print 5,5,5,5,5 Here how it solve using IIFE i.e Immediate Invoking Function Expression (function(j){ //i is passed here setTimeout(function(){ console.log(j); },1000); })(i); //look here it called immediate that is store i=0 for 1st loop, i=1 for 2nd loop, and so on and print 0,1,2,3,4 For more, please understand execution context to understand closure. - There is one more solution to solve this using let (ES6 feature) but under the hood above function is worked for(let i=0; i< 5; i++){ setTimeout(function(){ console.log(i); },1000); } Output: 0,1,2,3,4 |
JavaScript没有固有的隐私意识,所以我们使用函数范围(闭包)来模拟这个功能。
您所参考的So Answer是模块模式的一个例子,Addy Osmani很好地解释了学习JavaScript设计模式的重要性:
The Module pattern encapsulates"privacy", state and organization
using closures. It provides a way of wrapping a mix of public and
private methods and variables, protecting pieces from leaking into the
global scope and accidentally colliding with another developer's
interface. With this pattern, only a public API is returned, keeping
everything else within the closure private.