-
JS是一门编译语言,但其不像传统编译语言一样,不会提前编译,编译结果也不能在分布式中进行移植。JS的编译大部分情况下发生在代码执行前的几微秒。
-
传统编译过程:词法分析->语法分析->代码生成。
-
LHS和RHS查询:LHS查询是查找变量本身,RHS查询是查找变量的值。
-
词法作用域:定义在词法分析阶段的作用域,是由你在写变量时将变量和块作用域写在哪里决定的。
-
欺骗词法:
- 欺骗词法作用域会导致性能下降
- eval和with可以用来欺骗词法
-
提升:
- 在JS中,函数和变量声明都会被提升,例如:
a = 2; var a; console.log(a); // 实际中,var a这条变量声明会被提升到作用域的顶部 var a; a = 2; console.log(a);
- 每个作用域都会进行提升。
- 函数声明会提升,但是函数表达式不会,例如:
foo(); // TypeError bar(); // ReferenceError var foo = function bar() { // ... }; // 提升之后 var foo; foo(); // TypeError bar(); // ReferenceError foo = function() { var bar = ...self... // ... }
- 函数优先,JS中函数会首先提升,其次是变量(这就是JS中一等公民吗),例如:
foo(); // 1 var foo; function foo() { console.log( 1 ); } foo = function() { console.log( 2 ); }; // 提升之后 function foo() { console.log( 1 ); } foo(); // 1 foo = function() { console.log( 2 ); };
- let/const声明的变量不会被提升,实际上编译器也会注意到后面的let声明,但不能在声明之前以任何方式引用未声明的变量。es6中的解释:
The variables are created when their containing Lexical Environment is instantiated but may not be accessed in any way until the variable’s LexicalBinding is evaluated.
变量在其包含的词法作用域被实例化时被创建,但在变量被词法绑定之前不能以任何方式被访问。在let声明之前的这段运行时间被称为“暂时性死区,temporal dead zone,简称TDZ”。
-
let声明的范围是块作用域,var声明的变量是函数作用域;let在全局作用域下声明的变量不会成为window对象的属性,var声明的会。
-
闭包:当函数可以记住并访问所在的词法作用域时,就产生了闭包,即使函数是在当前词法作用域外执行。
《你不知道的JS》读书笔记——作用域和闭包
Yukino
637
2021-12-29