JavaScript 闭包理解

本文参考自https://medium.com/dailyjs/i-never-understood-javascript-closures-9663703368e8

结合文末的例子一起看效果更佳


 

前置知识

  在了解闭包前要先了解js的执行上下文

当代码在ja中运行时,执行代码的环境非常重要,并将概括为以下几点:

 

 

全局作用域 -- 第一次执行代码的默认环境

 

 

函数作用域 -- 当执行流进入函数体时

 

 

(..) -- 我们当做 执行上下文 是当前代码执行的一个环境与作用域

 

 

当执行到函数声明的时候会把该声明放到当前的执行上下文中,比如在全局作用域中声明一个函数,这个函数的声明就会放到全局执行上下文

 

当去执行一个函数时,会创建一个新的执行上下文,我们叫做本地执行上下文


 

闭包

  闭包就是当一个函数被创建并传递或从另一个函数返回时,它会携带一个背包,背包中是函数声明时作用域内的所有变量。

 

  一个本地执行上下文的相关的参数的会先在闭包中寻找, 如果没有则会不断往上层执行上下文寻找, 如果一致没找到, 这个参数默认为undefined, 

 

  

  函数最后遇到return或者右括号, 则会将结果返回调用上下文中, 并且将该本地执行上下文销毁, 所以当一个执行上下文返回一个函数定义时, 定义它的名字最后会被销毁, 存在于调用上下文中的函数声明是匿名的


 

例子

 1 // 前面的序号代表执行步骤
 2 
 3 function createCounter(){ // 1. 运行到此处, 将createCounter函数定义放入全局执行上下文
 4     let counter = 0; // 4.在本地执行上下文中声明新变量counter并赋为0
 5     const myFunction = function(){ // 5.将myFunction函数声明放入本地执行上下文
 6         counter = counter + 1; // 8. 先在闭包中看看有没有counter, 发现存在为0的counter, 将其值设置为1后再次存储在闭包中
 7         return counter;
 8     }
 9     return myFunction; // 6.返回myFunction函数定义和它的闭包, 闭包包括创建它时在作用域内的变量, 并将该本地执行上下文删除, myFunction和counter不再存在
10 }
11 
12 const increment = createCounter(); // 2.在全局执行上下文中声明increment新变量
13 // 3.然后调用creteCounter, 这时会创建一个新的本地上下文
14 
15 const c1 = increment(); // 7. 声明新变量, 执行函数, 执行的是之前返回的myFunction函数定义, 不过实际上不叫myFunction
16 const c2 = increment(); // 9. 与7类似, 只有由于闭包中的counter变化了, 所以结果也会有所不同
17 const c3 = increment();
18 
19 console.log("example increment",c1,c2,c3); // 1 2 3

 

 

posted @ 2019-11-29 14:04  aukocharlie  阅读(230)  评论(0编辑  收藏  举报