javascript 中的闭包

理解必包三个基本事实

1. JS允许你引用在当前函数以外定义的变量。

ex:

function makeSandwich(){

var magicIngredient = “peanut butter”;

function make(filling){

return magicIngredient +’ and ‘+ filling;

}

return make(‘jelly’);

}

makeSandwich();

 

2. 即使外部函数已经返回,当前函数仍然可以引用在外部函数所定义的变量。这意味着,你可以返回一个内部函数。

ex:

function mkSandwich(){

var magicIngredient = ‘peanut butter’;

function make (filling){

return magicIngredient +’ and ‘+filling;

}

return make;

}

var mk =  mkSandwich();

mk(‘jelly’);

mk(‘bananas’);

mk(‘marshmallows’);

 

Javascript函数值在内部存储它们可能会引用的定义在其封闭作用域的变量。

那些在其所涵盖的作用域内跟踪变量的函数被称为闭包。

make函数就是一个闭包,引用两个外部变量: magicIngredient和filling。

函数可以引用在其作用域内的任何变量,包括参数和外部函数变量。

ex: 

function mkSandwich(magicIngredient){

function make(filling){

return magicIngredient + ’and’ + filling;

}

return make;

}

var mk = mkSandwich(‘peanut butter’);

mk(‘jelly’);

mk(‘cheese’);

var mkspeical = mkSandwich(’turkey’);

mkspeical(’swiss’);

mkspeical(‘provolone’);

 

构建闭包的字面量语法-函数表达式

ex:

function mkSandwich(magicIngredient){

return function(filling){

return magicIngredient +’  and ‘+ filling;

}

}

 

3. 必包可以更新外部变量的值。实际上必包存储的事外部变量的引用,而不是它们值的副本。

ex:

function box(){

var val = undefined;

return {

set : function(newVal){

val = newVal;

},

get : function(){

return val;

},

type : function(){

return typeof val;

},

}

}

var boxdemo = box();

boxdemo.type();

boxdemo.set(998);

boxdemo.get();

boxdemo.type();

 

 

要搞清楚闭包,首先要知道javascript中的作用域.

 

什么是作用域,你可以简单的理解成当前上下文环境.

 

javascript 中的作用域有2种

属于全局作用域.

属于局部作用域

 

全局作用域:

比如我们在浏览器端编写的 javascript 代码,

1

var name=‘test’;

我们直接定义了一个变量name ,那么这个变量当前作用域就是全局,对于浏览器端全局就是window

更确切的说,name 是window 对象的一个属性.

1

2

3

console.log(window.name); //test

console.log(name); //test

console.log(this.name); //test

 

上面三种输出方法,结果都是一样的,因为当前作用域就是window对象,this指向当前作用域.

 

 

局部作用域:

此类作用域是针对javascript中函数的作用域.

是指在函数内部定义的变量,如下:

1

2

3

4

function test(){

    var name=‘yijiebuyi’;

    alert(this.name);

}

 

上面 name 是一个局部变量,定义在函数内部,所以它的作用域就是此函数内部可以访问.

alert(this.name);  this 指向当前作用域,因为在函数内部,所以指函数作用域.

 

如果函数外部  alert(name); 将会报错,返回 undefined

但是 函数内部可以访问函数外部作用域,如下:

1

2

3

4

var name=‘test’;

function test(){

   alert(name); //test

}

上面的代码没有问题,函数内部作用域可以访问全局作用域,(或者简单理解成 函数内部作用于可以访问它父级作用域)

 

既然函数可以访问父作用域变量,而且函数是一等公民,可以当做参数,返回值等.

那么问题来了:

1

2

3

4

5

6

function test(){

    var name=‘yijiebuyi’;

    return function(){

        console.log(name);

    }

}

1

2

var rtn=test();

rtn(); //yijiebuyi

我们上面运行 rtn() ,得到 yijiebuyi,说明了2个问题:

1.函数确实是头等公民,可以当参数,可以当返回值.

2.函数可以访问它的父作用域,因为成功输出了 yijiebuyi

 

我们再换一个思路:

如果我不返回这个匿名函数,但是我想得到 test 函数中的 name 属性值,怎么办?

好像不行,办不到,只能返回一个函数来获取 test 函数内部变量了,其实这个过程就是 一个典型的闭包!

 

我们在返回匿名函数的时候并没有返回 var name=‘yijiebuyi’  但是运行 rtn 函数却得到了 name 属性值.

 

所以:

闭包的作用就是:把函数内部私有变量暴露出来. (暴露作用域)

闭包如何实现:函数里面返回一个函数.

 

这个返回函数自动带上了父函数所在的作用域,所以可以访问其内部变量,

也正是因为闭包的存在,导致父函数执行完成后并没有被垃圾回收,它的作用域内的变量都将保存在内存中供闭包使用.

原文地址:https://www.cnblogs.com/papajia/p/4498218.html