每天了解一点JavaScript——作用域和闭包

1、闭包允许函数访问并操作函数外部的变量。只要变量或函数存在于声明函数时的作用域内,闭包就可使函数能够访问这些函数或变量。每一个通过闭包访问变量的函数都具有一个作用域链,作用域链包含闭包的全部信息。闭包是javascript 作用域规则的副作用。当函数创建时所在的作用域消失后,仍然能够调用函数。

2、回调函数指的是在将来不确定的某一时刻异步调用的函数,在回调函数中经常需要访问外部的数据。

3、闭包内的函数不仅可以在创建的时刻访问,同时当闭包内部的函数执行时,还可以更新这些变量的值。闭包不仅仅是在创建那一时刻的状态的表征,而是一个真实的状态的封装和存在,只要闭包存在,就可以对变量进行修改。

4、javascript代码有两种类型: 一种是全局代码,在所有函数外部定义;一种是函数代码,在函数内部。javascript 引擎执行代码时,每一条语句都处于特定的执行上下文中。Javascript 中有两种执行上下文——全局执行上下文和函数执行上下文。全局执行上下文只有一个,当javascript 程序开始执行时就已经创建了全局上下文;函数上下文是在每次调用函数时,就会创建新的函数上下文。

5、javascript 基于单线程的执行模型: 在某个特定的时刻只能执行特定的代码。一旦发生函数调用,当前的执行上下文必须停止执行,并创建新的函数执行上下文来执行函数。当函数执行完后,将函数执行上下文销毁,并重新回到发生调用时的执行上下文中。(这个跟汇编语言里的堆栈有点类似,也跟dsp中的中断的思维比较像)。所以需要跟踪执行上下文,包括正在执行的上下文以及正在等待的上下文。最简单的跟踪方法是使用执行上下文栈(调用栈)

6、无论何时创建函数,都会创建一个与之相关联的词法环境,并储存在Environment 的内部属性上;每次调用函数时,都会创建一个新的执行环境,并被推入执行上下文栈,同时还会创建一个与之相关联的词法环境。当执行函数语句时,需要查找标识符或者变量的值,js引擎首先查找当前的执行上下文,如果找不到就往外面的环境层层向外查找,。。。。。

7、javascript 的变量类型:可以通过安格关键字来定义变量:var、const 和let 。其中const 和 let 是在ES6 的时候加进javascript的。通过 const 定义的变量是不可变的,通过const定义的变量的值只能设置一次。通过var 和 let 声明的变量的值可以变更无数次。const 声明的变量只能被初始化一次,之后不能将全新的值再赋值给const变量,但是可以修改 const 变量已有的对象,像给对象添加属性;或者增加const变量指向的数组的长度,如用push()方法。

8、var 声明的变量总是在距离最近的函数内或者全局词法环境中注册的,而忽略块级作用域;这就导致在块级作用域内定义的变量,在块级作用域外仍能够被访问到;而let和const 直接在最近的词法环境中定义变量(可以是循环内、块级作用域内、函数内或者全局环境内),也就是说可以利用const 和 let 定义块级别、函数级别、全局级别的变量。

9、javascript 代码的执行分为两个阶段:(1)、一旦创建了词法环境,就执行第一阶段,没有执行代码,js引擎访问并注册当前词法环境中所声明的变量和函数。然后执行第二阶段,如何执行取决于变量的类型和环境的类型:

(用鼠标画流程图真好玩^--^)

扫描二维码关注公众号,回复: 5311475 查看本文章

10、比较怪异的是,虽然代码是一行一行执行的,但是可以在函数声明前访问函数;但是对于函数表达式和箭头函数并不能在声明之前访问。处于第二阶段说明函数已经通过函数声明进行了定义,在当前词法环境创建时已在其他代码执行之前注册了函数标识符,所以在执行函数调用前,要被调用的函数已经存在。

控制台输出的为三个  true,说明了函数可以在声明之前调用 

(函数表达式和箭头函数不能在声明前调用)

9、变量提升:变量的声明提升至函数顶部,函数的声明提升至全局代码的顶部。但是事实上,变量和函数的声明并没有发生实际的移动,只是javascript的编译和词法环境的作用,使他看起来像发生了提升。

来两道练习题试下:

var 和 let 的区别是什么: 关键字 var 用于定义函数作用域或全局作用域的变量,而let 允许定义块级作用域、函数作用域、全局作用域的变量。

闭包消耗的是内存成本

闭包允许函数访问函数创建时所在的作用域内的变量,而不是调用时所在的作用域内的变量。

猜你喜欢

转载自blog.csdn.net/Jackshijin/article/details/86536501