Javascript语言特有的”链式作用域”结构(chain scope),子对象会一级一级地向上寻找所有父对象的变量。父对象的所有变量,对子对象都是可见的,反之则不成立。
应用背景:
1)有时候需要得到函数内的局部变量,那就是在函数的内部再定义一个函数。
2)让变量的值始终保持在内存中。
一、闭包的概念:
个人理解:闭包就是能够读取其他函数内部变量的函数。由于在Javascript语言中,只有函数内部的子函数才能读取局部变量,因此可以把闭包简单理解成”定义在一个函数内部的函数”。
所以,在本质上,闭包就是将函数内部和函数外部连接起来的一座桥梁。
function w(){
var c = "开创独立王国的闭包";
var n = 1;
function b() {
console.log(c+'----打印'+n+'次');
n++;
}
return b;
}
var f1 = w()
f1()//开创独立王国的闭包----打印1次
f1()//开创独立王国的闭包----打印2次
官方对闭包的定义:所谓“闭包”,指的是一个拥有许多变量和绑定了这些变量的环境的表达式(通常是一个函数),因而这些变量也是该表达式的一部分。
结合以上示例,分析官方定义:
1、环境的表达式(通常是一个函数)—指的是函数b;
2、b拥有很多变量:c、n…;
3、b绑定了这些变量,比如b绑定了n;每次通过f1执行完b后,b的执行上下文n不消失,可以每次叠加。
4、这些变量也是该表达式的一部分:c、n确实是b函数的一部分。
闭包的意义在于:
1)js有两个作用域:全局作用域,函数的局部作用域;
2)局部作用域内可以访问全局作用域,但是全局作用域内却无法访问局部作用域。
二、闭包的特点:
1)可以访问父级函数的变量;
2)闭包函数内的this指向window;
var name = "The Window";
var object = {
name : "My Object",
getNameFunc : function(){
return function(){
return this.name;
};
}
};
alert(object.getNameFunc()());//The Window
3)不能直接访问父级函数的this和arguments;
闭包函数,也是一个内部函数,内部函数不能直接访问父级函数的this和arguments;可以通过在父级函数内将this和arguments赋值给变量,再通过访问父级函数变量的方式访问。
//不能直接访问父级函数的this
var name = "The Window";
var object = {
name : "My Object",
getNameFunc : function(){
return function(){
return this.name;
};
}
};
alert(object.getNameFunc()());//The Window
//将父级函数的this赋值给that变量,通过that访问父级函数的this
var name = "The Window";
var object = {
name : "My Object",
getNameFunc : function(){
var that = this;
return function(){
return that.name;
};
}
};
alert(object.getNameFunc()());//My Object
4)闭包函数使用的变量会被存入内存;
闭包函数所产生的上下文环境中包含的变量会被存入内存,不会随调用结束而被销毁,只有刷新或关闭浏览器才销毁。
三、案例:
难点闭包示例:
function w(){
var c = 8;
console.log("w被执行了")
function b() {
console.log(c);
c++;
}
return b;
}
console.log(w());
// b() {
// console.log(c);
// c++;
// }
w()()//8 每次调用的时都是重新定义c
w()()//8
w()()//8
var d = w();//d是指向window,把w存储在window下
d()//8 每次调用时,只是对定义在内存当中的c进行改变
d()//9
d()//10
console.log(c) //undefined c被存储起来,但是c不是在window下(重点不太好理解)
原因:d是创建国家d后,特工d多次执行命令的过程,因此对原来的国家d的变量改变是叠加的;w()()实际上时不断地创建新国家和新特工;
四、深探闭包:
整个js程序是最大的函数,程序一旦执行,就会产生一个全局的上下文,只要程序处于执行中,这个全局上下文永远不会消失,直至结束整个程序。
五、结语:
1、闭包是指有权访问另一个函数作用域中的变量的函数,创建闭包的最常见的方式就是在一个函数内创建另一个函数,通过另一个函数访问这个函数的局部变量。由于闭包会使得函数中的变量都被保存在内存中,内存消耗很大,所以不能滥用闭包,否则会造成网页的性能问题。解决方法是,在退出函数之前,将不使用的局部变量全部删除。
2、不必纠结到底怎样才算闭包,其实你写的每一个函数都算作闭包,即使是全局函数,你访问函数外部的全局变量时,就是闭包
的体现。
参考:
作者 ybdt1201
地址 https://blog.csdn.net/ybdt1201/article/details/53366613
作者 ruanhongbiao
https://blog.csdn.net/qappleh/article/details/80320476