作用域(又称为执行环境, execution context)定义了变量或函数有权访问的其他数据。在 JavaScript 中每个作用域都有一个与之关联的变量对象(variable object),作用域中定义的所有变量和函数都保存在这个对象中。
JavaScript 中最常见的作用域是函数作用域,其变量对象为函数的活动对象(activation object)。
尽管函数作用域是最常见的作用域单元,但在 JavaScript 中也存在其他类型的作用域单元。
with
with
通常被用于重复引用同一对象中的多个属性。
var obj = {
a: 1
}
with (obj) {
a = 2;
}
console.log(obj.a); // 2
使用 with
语句可以不需要重复引用对象本身,但可能会产生一些副作用。
var obj = {}
with (obj) {
a = 2;
}
console.log(obj.a); // undefine
console.log(a); // 2
上面的代码中,由于 obj
对象本身并不包含 a
属性,而 with
语句并不会为对象创建属性,并在非严格模式下创建了一个全局变量。
实际上, with
语句根据传递给它的对象创建了一个词法作用域。
注:尽管 with
块恶意将一个对象处理为词法作用域,但在这个块内部使用 var
声明的变量并不会被限制在这个块作用域中,而是被添加到 with
块所处的函数作用域中。
try/catch
try/catch
语句中的 catch
分句会创建一个块级作用域。
try {
undefined(); // 执行一个非法操作来强行制造一个异常
} catch (err) {
console.log(err); // TypeError: undefined is not a function
}
console.log(err) // Exception: ReferenceError: err is not defined
上面的代码中,变量 err
仅存在于 catch
分句中。
let
ES6 中引入了 let
关键字,提供了除 let
外的另一种变量声明方式。
if (true) {
let a = 1;
console.log(a); // 1
}
console.log(a); // Exception: ReferenceError: bar is not defined
let
关键字可以将变量绑定到所在的块中(通常是在一对花括号中),即 let
为其声明的变量隐式地创建了块级作用域。可以为块级作用域显式地创建块使得变量的附属关系变得更加清晰。
if (ture) {
{ // 显式地创建块
let bar = 1;
console.log(a); // 1
}
}
console.log(a); // Exception: ReferenceError: a is not defined
注:使用 let
进行的声明不会在块作用域中进行提升。
const
ES6 中引入的 const
关键字同样可以创建块级作用域,但与 let
关键字不同的是,使用 const
关键字创建的变量的值是固定的,即常量,之后任何试图修改常量的值的操作都会引起错误。
if (true) {
const a = 1;
a = 2; Exception: TypeError: invalid assignment to const a
}
console.log(a); // Exception: ReferenceError: a is not defined