首先,一个函数不管是不是匿名函数,和闭包之间根本没有任何关系!
所谓闭包究竟是什么?网络上说法云里雾里,讲得高深莫测,但是其实只要稍微有一些编译器实现机制的认识,就会知道闭包其实是非常简单的东西。
我们先来看看下面的代码:
1
2
3
4
5
6
7
8
9
10
11
12
function funcA() {
var a = 1, b = 2
return funcB()
function funcB() {
// 注意,a 和 b 在本函数里根本没有定义,但是竟然能访问到
return a + b
}
}
var a = funcA()
// a 将会等于 3
上面的代码神奇的地方有几点:
1、函数可以嵌套定义(而 C/C++ 就不行)
2、嵌套的函数可以访问到它的上级函数的局部变量
先说嵌套,其实这个能力没什么神奇的,C/C++ 编译器稍作修改就能支持,但是这么实现出来,虽然函数可以嵌套了,实用价值还是比较小,因为访问不到上级函数的局部变量啊。而且我们知道 Javascript 的嵌套函数是可以层层嵌套的,而访问时最内层的函数也能够访问到最顶层的函数的变量,非常有用!
说到这里,和闭包有什么关系呢?
闭包,就是用来实现这种嵌套时还能够层层向上访问变量的功能的!对的,它就是一个简单的编译器技巧,用来使得内部函数能够访问上级函数的变量。
简单来说,它具体实现的方法为,在每个函数上附加上一个额外的隐藏对象,这个对象其实就叫做闭包对象,你别管他名字怎么叫,它就是个普通的对象!它没什么神奇的,就是记录了本函数内部的变量列表而已。而且这个闭包对象还保存了一个指向上级函数的闭包对象的引用。
这样一来,就形成了一个链条。当我们在一个函数里访问一个变量的时候,编译器会先看看在本闭包里到底有没有这个变量,如果没有就向上寻找。如果找到,那就用,如果一直找到头也没有,那就提示出错。
明白了吗?就是这么回事。但是最后还有一点,按照上面的方式构造出来的闭包好像是固定的,其实每次调用一个函数的时候,都会单独创建一个新的闭包对象和这一次调用对应起来。因此其实闭包链是动态创建的。
其实要说清楚这个问题,得配几个图。但是时间所限,我就不细说了。如果你能理解那最好,如果还是有疑问,那你以后慢慢接触得多了就知道了。
最后解释一下这段代码,加深理解
1
2
3
4
5
function X() {
return function() {
// ...
}
}
注意X里面这里返回了一个匿名函数。一定要记住这个函数由于是嵌套定义在 X 里的,因此它的闭包对象是链接到 X 的闭包对象上的,所以在这个匿名函数里是可以访问到 X 内部的变量的。其实就是这么简单。不管你嵌套多少层,匿名还是有名。我只看你定义时的嵌套关系,就知道闭包链的整个链条!其他就顺理成章了。
最后推荐两个让你走出国内普遍存在的误区的方法,一是多看 ECMA-262, 5e,这里面包含了所有标准化的 Javascript 的算法实现细节。另外一个是研究 Google 的 v8 引擎。自己下代码下来编译调试下,很多问题就能搞清楚了。
就说这么多了。
var MyFn={say:function(str){
alert(str)
},
}
MyFn.say("lalala")
最好是这样用jquery
(function($){
$.MyJq={
say:function(str){alert(str)}
}
}
)(jQuery)
这样你以后只要用$.MyJq.say()就可以使用了。里面的变量也不会被其他的外面的变量顶了。不过保证MyJq不被重复
你这个代码哪里形成闭包了?
这么说吧,任何函数和其定义时所处环境都构成闭包,只是你的代码中没有体现对闭包的应用吧
纠正一点,任何在函数中定义的变量都是在函数的私有作用域中,所谓全局作用域只存在global对象中(浏览器中的window)
我们通常说闭包,是说在外部函数内部定义的函数引用了在外部函数定义的变量,在外部函数执行完成时,造成该变量对应内存没有被回收,于是内部函数与这个变量就形成了闭包
比如
function A() {var i = 1
return {
B: function () {
alert(i)
},
C: function () {
i++
}
}
}
var D = A()
D.B()
D.C()
D.B()
对于A来说,A执行完,在A中的局部变量所占内存应该销毁
函数B,函数C的定义中引用了A的私有变量i ,B和i 就形成闭包 ,C和i也形成闭包,造成GC不能回收i所占内存, 但是只有在B,C中能访问到i,外部是无法直接访问i的,外部只有通过B,C才能访问i,在外部看来i就是A的私有变量啊