首页 > 编程语言 > 详细

javascript与闭包

时间:2020-03-22 10:24:15      阅读:88      评论:0      收藏:0      [点我收藏+]

定义

闭包就是能够读取其他函数内部变量的函数。在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对象是运行时基于函数的执行环境绑定的:在全局函数中,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

 

javascript与闭包

原文:https://www.cnblogs.com/w04301706/p/12544028.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!