1.作用域的嵌套
在当前作用域中无法找到某个变量时,引擎就会在外层嵌套的作用域中继续查找,直到找到该变量,或抵达最外层的作用域(全局)为止。
LHS 查询和 RHS查询:如果查找的目的是对变量进行赋值,则使用LHS查询;如果目的是获取变量的值,则使用RHS查询
- 不成功的LHS引用会导致自动隐式地创建一个全局变量(非严格模式下)
- 不成功的RHS引用会导致抛出ReferenceError
2.词法作用域
查找 始终从运行时说出的最内部作用域开始,逐级向外/向上运行,知道遇到第一个匹配的标识符为止。
遮蔽效应:在多层的嵌套作用域中可以定义同名的标识符,内部的标识符“遮蔽”了外部的标识符,这被称为~。
词法作用域完全由写代码期间函数所声明的位置定义。
欺骗词法
欺骗词法(运行时修改词法作用域) ——— 导致性能下降,不建议使用
有两种机制实现(但并不推荐)
- eval()
- with
3.函数作用域和块作用域
3.1 函数中的作用域
含义: 属于这个函数的全部变量都可以在整个函数的范围内使用及复用(嵌套的作用域中也可)。
“隐藏”作用域中的变量和函数:符合最小授权/最小暴露原则;规避冲突
区分函数声明和表达式的方法:看function位置。function是声明中的第一个词,则是函数声明,否则是函数表达式。
3.2 块作用域
- with —— 用with创建出的作用域仅在with声明中而非外部作用域中有效
- try/catch —— 声明的变量仅在catch内部有效
- let —— ES6引入的新let关键字,可以为其声明的变量隐式所在的块作用域
- const —— 类似于let,但其值是固定的(常量)
4.变量提升
函数声明会被提升,但函数表达式不会。
//函数声明
function foo {
console.log(a); //undefined
var a = 2;
};
等价于
//函数声明
function foo {
var a;
console.log(a); //undefined
a = 2;
};
但在函数表达式中,则不会发生提升
//函数表达式
foo(); //TypeError! (而不是ReferenceError)
bar(); //ReferenceError!
var foo = function bar (){
// ...
};
实际上其等价于:
//函数表达式
var foo;
foo(); //TypeError! (而不是ReferenceError)
bar(); //ReferenceError!
foo = function (){
var bar = ...self...
// ...
};
注: 函数声明和变量声明都会被提升,但函数优先。