闭包概念
闭包(closure)是 Javascript 语言的一个难点,也是它的特色,很多高级应用都要依靠闭包实现
理解闭包,首先必须理解变量作用域
变量的作用域
要理解闭包,首先必须理解Javascript特殊的变量作用域
变量的作用域无非就是两种
- 全局变量
- 局部变量
另一方面,在函数外部自然无法读取函数内的局部变量var n = 100;function getNum(){console.log(n);}getNum(); // 100
⚠️注意:这里有一个地方需要注意,函数内部声明变量的时候,一定要使用var命令。如果不用的话,你实际上声明了一个全局变量function getNum(){var n = 100;}console.log(n); // error
如何从外部读取局部变量
出于种种原因,我们有时候需要得到函数内的局部变量。但是,前面已经说过了,正常情况下,这是办不到的,只有通过变通方法才能实现
那就是在函数的内部,再定义一个函数
既然getN可以读取getNum中的局部变量,那么只要把getN作为返回值,我们不就可以在getNum外部读取它的内部变量了吗
function getNum(){var n = 100;function getN(){console.log(n);}return getN;}var result = getNum();result(); // 100
闭包的概念
上述代码中的getN函数就是闭包
各种专业文献上的”闭包”(closure)定义非常抽象,很难看懂。我们参考老前辈的理解是:闭包就是能够读取其他函数内部变量的函数
由于在Javascript语言中,只有函数内部的子函数才能读取局部变量,因此可以把闭包简单理解成”定义在一个函数内部的函数“
所以,在本质上,闭包就是将函数内部和函数外部连接起来的一座桥梁
闭包特点
- 读取函数内部的变量
- 变量的值始终保持在内存中
读取函数内部的变量
function getNum(){var n = 100;function getN(){console.log(n);}return getN;}var result = getNum();result(); // 100
变量的值始终保持在内存中
观察多次调用函数,n的变化 ```javascript function getNum(){ var n = 100; n++; console.log(n); }
getNum(); // 101 getNum(); // 101
增加闭包,在观察n的变化```javascriptfunction getNum() {var n = 100;nAdd = function () {n += 1}function getN() {console.log(n);}return getN;}var result = getNum();result(); // 100nAdd();result(); // 101
使用闭包的注意点
由于闭包会使得函数中的变量都被保存在内存中,内存消耗很大,所以不能滥用闭包,否则会造成网页的性能问题
闭包应用场景
创建一个函数,声明一个数组,然后向入组中放入一个函数,函数值为i * i
function count() {var arr = [];for (var i = 1; i <= 3; i++) {arr.push(function () {return i * i;});}return arr;}var results = count();var f1 = results[0];var f2 = results[1];var f3 = results[2];console.log(f1(),f2(),f3()); // 16 16 16
原因就在于返回的函数引用了变量i,但它并非立刻执行。等到3个函数都返回时,它们所引用的变量i已经变成了4,因此最终结果为16
返回闭包时牢记的一点就是:返回函数不要引用任何循环变量,或者后续会发生变化的变量
如果一定要引用循环变量怎么办?方法是再创建一个函数,用该函数的参数绑定循环变量当前的值,无论该循环变量后续如何更改,已绑定到函数参数的值不变
function count() {var arr = [];for (var i = 1; i <= 3; i++) {arr.push((function (n) {return function () {return n * n;}})(i));}return arr;}var results = count();var f1 = results[0];var f2 = results[1];var f3 = results[2];f1(); // 1f2(); // 4f3(); // 9
闭包中的this关键字
闭包中的this永远指向window
var name = "The Window";var object = {name : "My Object",getNameFunc : function(){return function(){return this.name;};}};alert(object.getNameFunc()());
var name = "The Window";var object = {name : "My Object",getNameFunc : function(){var that = this; //this的指向是可以被改变的return function(){return that.name;};}};alert(object.getNameFunc()());
