js作用域
先说结论,在 JavaScript 中,作用域只有两种。全局作用域(window)和局部作用域(函数)。
全局作用域中的所有对象均为 window 对象的属性。局部作用域(函数)中的所有对象在整个函数范围内均是可见的,也就是说 JavaScript 没有类似其他语言中的块级作用域。
作用域链
当发生变量的调用时,调用方先在当前局部作用域(作用域链的第一个对象)寻找变量,没有的话沿着作用域链向着外层局部作用域(作用域链的第二个对象)寻找变量,还没有的话就继续沿着链寻找全局变量(作用域链的最后一个对象)。
下述代码中涉及到的作用域对象分别是inner->outter->window
1 | var hello = 1; |
函数体内部局部变量的优先级高于全局变量
这一点和其他语言类似,如以下代码所示:
1 | var hello = 1; //定义全局变量 hello |
但需要注意的是以下代码所示的这种情况:
1 | var x = 1; |
由于 JavaScript 的解释执行机制分为两步,分别是预编译(预处理)和解释执行,在预处理的时候已经发现了局部变量 x,由于同名局部变量的优先级高于全局变量。所以在执行的时候,func 中局部变量 x 的优先级最高。预编译时期也只进行变量和函数的声明,后续的定义在执行时期才能发生。于是这里的第一个 x 是 ‘undefined’。
JavaScript 不存在块级作用域
如下所示:
1 | function func() { |
可见,在函数之内的所有非嵌套函数内声明的变量均是可见的,说明 JavaScript 没有传统意义上的块级作用域。这也说明,JavaScript 只有函数和 window 作用域
不以 var
声明的变量是全局变量
1 | <script type="text/javascript"> |
没有使用 var
声明的变量,均为 window 作用域的全局变量,即便声明存在于函数中。
注
在Node.js 的 REPL 环境下,a 是全局变量,被挂载在 global 对象之下。在 Node.js 的模块环境之下,全局变量必须显式声明称 global 对象的属性。或者不使用 var 修饰。
browser 下两者都会被视为全局变量。
标签的作用域
标签的作用域只限于本代码块内,在全局作用域无效,也不会被块内函数继承,以下代码将报错:
1 | list: { |
正确的写法:
1 | list: { |