Javascript闭包
时间:2021-06-02 18:52:21
收藏:0
阅读:0
每个函数在调用时,都会创建一个执行环境。这个执行环境有它的变量对象以及作用域链。通过作用域链,可以访问上层的作用域的内容。
闭包的概念:
闭包是能够访问另一个函数作用域中变量的函数(这个“另外一个函数”,通常指的是包含闭包函数的外部函数)
function outerFunction () { var a = 1 return function () { console.log(a); } } var innerFunction = outerFunction(); innerFunction();
在这个例子里:负责打印a的匿名函数被包裹在外部函数outerFunction里面,且访问了外部函数outerFunction作用域里的变量a,所以从定义上说,它是一个闭包。
谈谈函数执行环境,作用域链以及变量对象
作用域和执行环境其实是同一个概念
先引用一下《javaScript高级语言程序》中的两段原话:
1. "当某个函数被调用时,会创建一个执行环境 (execution context)及相应的作用域链(scope Chain)" — —第178页 7.2 闭包
2. "每个执行环境都有一个与之关联的变量对象(variable object),环境中定义的所有变量和函数都保存在这个对象中" — — 第73页 4.2 执行环境及其作用域
执行环境(execution context),作用域链(scope Chain)以及变量对象(variable object),但这三者们具体是什么关系呢?
汤姆大叔的文章中的伪代码:
ExecutionContext = { variableObject: { .... }, this: thisValue, Scope: [ // Scope chain // 所有变量对象的列表 ] };
所以说,在函数调用的时候,会创建一个函数的执行环境,这个执行环境有一个与之对应的变量对象和作用域链。
每个函数的变量对象保存了它所拥有的数据,以供函数内部访问和调用,这些数据包括:(位于执行环境内部的)
1.声明变量
2.声明函数
3.接收参数
例如:
function foo (arg) { var variable = ’我是变量‘; function innerFoo () { alert("我是彭湖湾") } } foo(‘我是参数‘);
这个时候执行环境对应的变量对象就变成了这样:
ExecutionContext = { variableObject: { variable:’我是变量‘ innerFoo: [对函数声明innerFoo的引用] arg: ‘我是参数‘ }, this: thisValue, Scope: [ // Scope chain // 所有变量对象的列表 ] };
作用域链的作用:
通过作用域链,函数能够访问来自它上层作用域(执行环境)中的变量
看个例子:
function foo () { var a = 1; function innerFoo () { console.log(a) } innerFoo(); } foo(); // 打印 1
作用域链其实就是个从当前函数的变量对象开始,从里到外取出所有变量对象,组成的一个列表。通过这个作用域链列表,就可以实现对上层作用域的访问。
闭包与函数柯里化多层嵌套的闭包,这种用法,叫做“柯里化”。 而闭包柯里化有两大作用:参数累加和延迟调用
function foo (a) { return function (b) { return function (c) { console.log(a + b + c); } } }foo(‘我‘)(‘叫‘)(‘彭湖湾‘); // 打印 我叫彭湖湾
从这里,我们可以很直观地看出闭包柯里化的时候参数累加的作用
我们把上面那个例子改变一下:
function foo (a) { return function (b) { return function (c) { console.log(a + b + c); } } } var foo1 = foo(‘我‘); var foo2 = foo1(‘叫‘); foo2(‘彭湖湾‘); // 打印 我叫彭湖湾
可以看到,最内层的闭包在外层函数foo和foo1调用的时候都没有调用,直到最后得到foo2并调用foo2()的时候,这个最内层的闭包才得到执行, 这也是闭包的一大特性——延迟执行
评论(0)