第一部分 作用域和闭包
第一章 作用域是什么
- 引擎:从头到尾负责整个JavaScript程序的编译及执行过程
- 编译器:负责语法分析及代码生成等
- 作用域:负责收集并维护由所有声明的标识符组成的一系列查询,并实施一套非常严格的规则,确定当前执行的代码对这些标识符的访问权限。
LHS和RHS查询
-
LHS查询是为了找到变量容器的本身从而对其赋值;
-
RHS查询时为了获取变量的值。
第二章 词法作用域
词法作用域就是定义在词法阶段的作用域,由写代码时将变量和块作用域写在哪里来决定,当词法分析器处理代码时会保持作用域不变。
在JS中有两个机制可以欺骗词法作用域:
-
eval(…)
对一段包含一个或多个声明的代码字符串进行演算并借此来修改已经存在的词法作用域。
-
with
通过将一个对象的引用当作作用域来处理,将对象的属性当作作用域中的标识符来处理,从而创建了一个新的词法作用域,
这两个机制的副作用是引擎无法在编译时对作用域查找进行优化,因为引擎只能谨慎地认为这样的优化是无效的,使用其中的任何一个机制都会导致代码变慢。!不要使用它们
第三章 函数作用域和块作用域
- try/catch结构在catch分句中具有块作用域;
- ES6中引入了let和const来创建块作用域变量。
- IIFE(Immediately Invoked Function Expression):立即执行函数表达式
第四章 提升
- js引擎将
var a = 2
看成是var a
和a=2
两个单独的声明,第一个是编译阶段的任务,第二个是执行阶段的任务,无论作用域中的声明出现在什么地方,都将在代码本身被执行前首先进行处理,这个过程被称为提升。
函数提升
-
函数声明会被提升,但函数表达式不会被提升
-
函数会先于变量被提升
-
重复的var声明会被忽略掉,但出现在后面的函数声明可以覆盖前面的。
-
下面的过程不会像代码暗示的那样被条件判断所控制(书上写的,现在js引擎的执行方式可以像下面代码暗示的被条件控制),行为并不可靠,在JS未来的版本中有可能发生改变,应尽量避免在块内部声明函数。
foo(); //TypeError: foo is not a function var a=true; if(a) { function foo() { console.log('a'); } } else { function foo() { console.log('b'); } }