闭包,有人说它是一种设计理念,有人说全部的函数都是闭包。我不知道如何去定义它,我也不许备去定义它,定义它就是限制了对它的理解。segmentfault
咱们依赖光来看清世间万物,光却遮住了黑暗。如同你脚下的路,让你看不清前行的方向。数组
在这里写一点我对闭包的理解。理解闭包的关键在于:外部函数调用以后其变量对象本应该被销毁,但闭包的存在使咱们仍然能够访问外部函数的变量对象。闭包
function outer() { var a = 1; return function() { return a; }; } var b = outer(); console.log(b()); //1
(function(){ var now = new Date(); if (now.getMonth() == 0 && now.getDate() == 1) { alert('Happy new Year!'); } })();
这种方式经常使用来限制向全局做用域添加过多的变量和函数。app
(funcion() { var a = 1; setA = function(val){ a = val; }; getA = function(){ return a; }; })(); console.log(a); //报错 console.log(getA()); //1 setA(2); console.log(getA()); //2
也能够这样写:函数
function outer(){ var a = 1; return { setA: function(val) { a = val; }, getA: function() { return a; } }; } var closure = outer(); console.log(a); //报错 console.log(closure.getA()); //1 closure.setA(2); console.log(closure.getA()); //2
第一个例子中,setA
,getA
都是全局变量,用于读写私有变量a
。第二个例子中将这两个方法做为一个对象返回并赋给一个全局变量closure
,这样当outer
执行完毕后,这两个方法(匿名函数)连同外部函数中的变量对象(a
)依然不会被销毁。this
闭包用于建立具备私有变量的实例对象,参考经过闭包建立具备私有属性的实例对象设计
function arrFunc() { var arr = []; for (var i=0; i<10; i++) { arr[i] = function() { return i; }; } return arr; }
arr
数组中包含了10个匿名函数,每一个匿名函数都能访问外部函数的变量i
,那么i
是多少呢?当arrFunc
执行完毕后,其做用域被销毁,但它的变量对象仍保存在内存中,得以被匿名访问,这时i
的值为10。要想保存在循环过程当中每个i
的值,须要在匿名函数外部再套用一个匿名函数,在这个匿名函数中定义另外一个变量而且当即执行来保存i
的值。code
function arrFunc() { var arr = []; for (var i=0; i<10; i++) { arr[i] = function(num) { return function() { return num; }; }(i); } return arr; } console.log(arrFunc()[1]()); //1
这时最内部的匿名函数访问的是num
的值,因此数组中10个匿名函数的返回值就是1-10。对象
this
var name = 'window'; var obj = { name: 'object', getName: function() { return function() { return this.name; }; } }; console.log(obj.getName()()); //window
obj.getName()()
其实是在全局做用域中调用了匿名函数,this
指向了window
。这里要理解函数名与函数功能是分割开的,不要认为函数在哪里,其内部的this
就指向哪里。window
才是匿名函数功能执行的环境。要想使this指向外部函数的执行环境,能够这样改写:内存
var name = 'window'; var obj = { name: 'object', getName: function() { var that = this; return function() { return that.name; }; } }; console.log(obj.getName()()); //object
arguments
与this
也有相同的问题。下面的状况也要注意:
var name = 'window'; var obj = { name: 'object', getName: function() { return this.name; } }; obj.getName(); //object (obj.getName = obj.getName)(); //window 非严格模式下
obj.getName();
这时getName()
是在对象obj
的环境中执行的,因此this
指向obj
。(obj.getName = obj.getName)
赋值语句返回的是等号右边的值,在全局做用域中返回,因此(obj.getName = obj.getName)();
的this
指向全局。要把函数名和函数功能分割开来。
闭包会引用包含函数的整个变量对象,若是闭包的做用域链中保存着一个HTML
元素,那么就意味着该元素没法被销毁。因此咱们有必要在对这个元素操做完以后主动销毁。
function assignHandler() { var element = document.getElementById('someElement'); var id = element.id; element.onclick = function() { alert(id); }; element = null; }
当函数内部的定时器引用了外部函数的变量对象时,该变量对象不会被销毁。
(function() { var a = 0; setInterval(function(){ console.log(a++); }, 1000); })();
闭包引用外部函数变量对象中的值;
在外部函数的外部调用闭包。
转载请注明出处:http://www.javashuo.com/article/p-dwwykxew-cv.html
文章不按期更新完善,若是能对你有一点点启发,我将不胜荣幸。