闭包就是能够读取其他函数内部变量的函数。在javascript中,只有函数内部的子函数才能读取局部变量,所以闭包可以理解成“定义在一个函数内部的函数“。在本质上,闭包是将函数内部和函数外部连接起来的桥梁。
闭包可以保存外部函数的变量,内部函数保留了对外部函数的活动变量的引用,所以变量不会被释放。可以用在把一些不经常变动计算起来又比较复杂的值保存起来,节省每次的访问时间。示例:
functions(){
vara=1;
returnfunction(){
returna;
}
}
vard=s();
console.log(d());
我们可以把函数当作一个范围,函数内部的变量就是私有变量,在外部无法引用,但是我们可以通过闭包的特点来访问私有变量,类似于高级编程语言封装的一个对象。
varperson=function(){
varname=‘default‘;
return{
getName:function(){
returnname;
},
setName:function(newName){
name=newName;
}
}
}();
console.log(person.getName());
person.setName(‘newName‘);
console.log(person.getName());
在JavaScript中没有块级作用域,只有函数作用域。JS不会告诉你变量是否已经被声明,所以容易造成命名冲突,如果在全局环境定义的变量,就会污染全局环境。
functionoutPutNum(count){
for(vari=0;i<count;i++){
console.log(i);
}
vari; //即使重新定义也没用
console.log(i); //这里还会输出for循环中的i的值
}
outPutNum(10);
因此可以利用闭包的特性来模仿块级作用域。
functionoutPutNum(count){
(function(){
for(vari=0;i<count;i++){
console.log(i);
}
})();
vari;
console.log(i); //i会变成undefined
}
outPutNum(10);
其实从堆栈的角度来看待闭包,对其就一目了然了。JavaScript每进入一个方法都会在内存栈上创建一个当前方法的执行环境,方法执行完之后释放该环境。
vara= 1;
functionfn(){
varb= 2;
functionfn1(){
console.log(b);
}
fn1();
}
fn();
栈是一种先进后出的数据结构:
1)在执行fn前,此时我们在全局执行环境(浏览器就是window作用域),全局作用域里有个变量a;
2)进入fn,此时栈内存就会push一个fn的执行环境,这个环境里有变量b和函数对象fn1,这里可以访问自身执行环境和全局执行环境所定义的变量
3)进入fn1,此时栈内存就会push 一个fn1的执行环境,这里面没有定义其他变量,但是我们可以访问到fn和全局执行环境里面的变量,因为程序在访问变量时,是向底层栈一个个找,如果找到全局执行环境里都没有对应变量,则程序抛出underfined的错误。
4)随着fn1()执行完毕,fn1的执行环境被杯销毁,接着执行完fn(),fn的执行环境也会被销毁,只剩全局的执行环境下,现在没有b变量,和fn1函数对象了,只有a 和fn(函数声明作用域是window下)
this对象是运行时基于函数的执行环境绑定的:在全局函数中,this等于window,而当函数被作为某个对象的方法调用时,this等于那个对象。把这个概念说得直白一点就是:看包含this的函数在被调用时,这个函数的前面有没有“.”,有“.”时this就指向“.”前面的对象,否则就是window对象。
varname= "The window";
varobject= {
name:"object",
getNameFunc:function() {
returnfunction() {
returnthis.name;
}
}
}
console.log(object.getNameFunc()());//The window
object.getNameFunc()()这个调用可以拆分为两步:
1、var first = object.getNameFunc();
//这里first= function () {
// return this.name;
// }
2、var second = first();
//这个函数的左边没有“.”,所以输出是“The window”。
那么如果想让object.getNameFunc()()输出“object”,应该怎么做呢?答案就是把this保存到闭包中:
varobject= {
name:"object",
getNameFunc:function() {
varthat=this;//把this保存到闭包的that变量中
returnfunction() {
returnthat.name;
}
}
}
1、var first = object.getNameFunc();
当执行到这句代码时,按照this的定义,getNameFunc里的this变量指向了object对象,that又指向了this,同时由于闭包有保存变量的作用,导致的结果就是that永远指向了object对象,而this则继续根据上下文自动变化。
2、var second = first();
这里执行了return that.name; 由于that变量一直指向object对象,所有最终会打印出”object”.
https://www.cnblogs.com/xiaotie/archive/2011/08/03/2126145.html
https://kb.cnblogs.com/page/110782/
https://www.jianshu.com/p/102e44f35b3b
https://www.cnblogs.com/sandaizi/p/11582488.html
https://www.jianshu.com/p/4e4e421907ba
https://www.cnblogs.com/nuanriqingfeng/p/5789003.html
原文:https://www.cnblogs.com/w04301706/p/12544028.html