什么是作用域?
这篇文章引用了《高性能JavaScript》这本书中一些作用域的知识,有兴趣的朋友可以看一看。
既然是JS基础类别的,自然就少不了JS作用域的知识。js中的作用域分为全局作用域和局部作用域。js中并没有 像java语言中的块级作用域。
全局作用域
var a = 0;
if (true) {
var b = 1;
}
console.log(b); // 输出1
像这样在全局中定义a
变量,为全局变量,在任何地方都能访问到这个a
变量。
因为js中没有块级作用域,所以在 if
或是 for
这样逻辑语句中定义的变量都是可以被外界访问到的。
局部作用域
局部作用域也可以称之为函数作用域。
function fn () {
var c = 2;
}
console.log(c); // 报错,c变量未定义
局部作用域中定义的变量,只供局部作用域调用,外界无法访问。
作用域链
Function对象有一个仅供 JavaScript 引擎存取的内部属性。
这个属性就是[[Scope]]
。[[Scope]]
包含了一个函数被创建的作用域中对象的集合。这个集合被称为函数的作用域链,它决定了哪些数据能被函数访问。
关于作用域链,局部作用域可以访问到全局作用域中的变量和方法,而全局作用域不能访问局部作用域的变量和方法。
var a = 0;
function fn () {
var b = 1;
console.log(a); // 输出 1
}
// 全局作用域并不能访问 fn 函数中定义的 b 变量
console.log(b); // 报错
fn();
当函数fn()
创建时,它的作用域中插入了一个对象变量,这个全局对象代表所有在全局范围内定义的变量。
当函数fn()
执行时,会创建一个名为执行环境的独一无二的内部对象。函数每执行一次,都会创建一个执行环境。当函数执行完毕,执行环境就会被销毁。
每个执行环境都有自己的作用域链,用来解析标识符。当执行环境被创建时,它的作用域就会初始化为当前运行函数的[[Scope]]
属性中的对象。
执行环境创建完成之后,就会生成一个"活动对象"
,这个对象包含了当前函数的所有局部变量
,命名参数
,参数集合
和this
。此对象会被推入作用域链的最前端。
当执行环境被销毁后,"活动对象"
也会随之被销毁。
如下图所示:
当fn()
时,会使用到a
变量,这时候就会搜索执行环境的作用域链,找到就使用,找不到就会到作用域链的下一个对象找,如果搜寻到最后,还没找到,那就认定这个变量是未定义的。