重新理解js的执行环境和闭包
Posted 造轮子
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了重新理解js的执行环境和闭包相关的知识,希望对你有一定的参考价值。
数学是美的,是一种精确的美。开发语言作为数学的一种映射,我相信也一定是美的,精确美。
最近突然发现对一些基本概念模棱两可甚至莫名其妙。我相信开发是具备精确性的所以我决定重新理解,确定这些概念的边界和内涵。
关于执行环境
执行环境是javascript中最为重要的一个概念。执行环境定义了变量或者函数有权访问其他数据,决定了他们各自的行为。
每个执行环境都有一个与之关联的变量对象。环境中定义的所有变量和函数都保存在这个对象中。全局执行环境是最外层的执行环境。
在JavaScript中每个函数都有自己的执行环境。当代码在一个执行环境中执行时,会创建变量对象的作用域链。作用域链保证对执行环境有权访问的所有变量和函数的有序访问。
作用域链的前端是当前执行的代码所在环境的变量对象。如果这个环境是函数,则将其活动对象作为变量对象。活动对象在最开水时只包含一个变量,即arguments对象(箭头函数没有这个)。作用域链中的下一个变量对象来自外部环境,而下一个变量对象则来自下一个包含环境。这样一直延续到全局执行环境。
关于作用域
作用域是一个范围。它的主体可以是变量或者函数。它可以分为全局作用域、局部作用域、块级作用域。
关于闭包
在《JavaScript高级程序设计》中,对闭包的定义是有权访问另一个函数作用域的变量的函数。按照这个定义闭包是一个函数。而且这个函数需要被另一个函数包裹。
而且有点比较重要:
一般来说函数执行完毕后,局部活动UI对象就会被销毁,内存中仅保存全局作用域。但是闭包不同,因为闭包的内部函数会引用外部函数变量,导致活动对象不会被销毁。而闭包的这种配置机制也就引起了一个副作用,即闭包只能取得包含函数中任何变量的最后一个值。
比如:
1 function createFunctions() { 2 const arr = [] 3 for (var i = 0; i < 10; i++) { 4 arr.push(function () { 5 console.log(i) 6 }) 7 } 8 return arr 9 10 } 11 12 createFunctions().forEach((fn)=>{ 13 fn() 14 })
但是还有这样的一种情形
1 // const arr = [] 2 for (var i = 0; i < 10; i++) { 3 arr.push(function () { 4 console.log(i) 5 }) 6 } 7 arr.forEach(function (fn) { 8 fn() // 输出的是10 9 })
上述两者的打印结果都是10。但原理不是一样的。
第一个是闭包行为,第二个是全局全局作用域一直存在,而执行完毕全局作用域的i是10。
当然要想解决上述问题只需要把var改为let即可。因为let具备块级作用域。因为存在块级作用域,循环中i只会在for循环的环境中,一旦脱离就不在存在,所以访问不到了,所以按部就班的输出。
以上是关于重新理解js的执行环境和闭包的主要内容,如果未能解决你的问题,请参考以下文章