js闭包循环原因_javascript与闭包

b8c2cc8cc3abecbae04decda0f1d8497.png

定义

闭包就是能够读取其他函数内部变量的函数。在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

console.log(i);

}

vari; //即使重新定义也没用

console.log(i); //这里还会输出for循环中的i的值

}

outPutNum(10);

因此可以利用闭包的特性来模仿块级作用域。

functionoutPutNum(count){

(function(){

for(vari=0;i

console.log(i);

}

})();

vari;

console.log(i); //i会变成undefined

}

outPutNum(10);

原理

其实从堆栈的角度来看待闭包,对其就一目了然了。JavaScript每进入一个方法都会在内存栈上创建一个当前方法的执行环境,方法执行完之后释放该环境。

vara= 1;

functionfn(){

varb= 2;

functionfn1(){

console.log(b);

}

fn1();

}

fn();

1a7ee5c059242922154f0353b2ab51a5.png

栈是一种先进后出的数据结构:

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对象是运行时基于函数的执行环境绑定的:在全局函数中,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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值