javaScript作用域以及作用域链
原创
©著作权归作者所有:来自51CTO博客作者qq5945ef689245b的原创作品,请联系作者获取转载授权,否则将追究法律责任
什么是作用域
作用域指的是变量存在的范围。
- 在 JavaScript 中, 对象和函数同样也是变量,可以理解作用域为可访问变量,对象,函数的集合
在 ES5
的规范中,JavaScript
只有两种作用域:一种是全局作用域,变量在整个程序中一直存在,所有地方都可以读取;
另一种是函数作用域,变量只在函数内部存在。ES6
又新增了块级作用域
全局作用域
所有顶层函数声明或者大括号之外定义的变量,都在全局作用域里。
function fxFn () {
fxs = 2
}
var fx = 1
console.log(window.fx) // 1
// console.log(fxs) 未定义
fxFn() // 执行后fxs成为全局变量
console.log(fxs) // 2
var声明的变量与不使用var声明的变量区别
局部作用域(函数作用域与块级作用域)
函数作用域
在 JavaScript
中,任何定义在函数体内的变量或者函数都将处于函数作用域中,这些变量通常无法被在函数外部使用
- 局部变量在函数开始执行时创建,函数执行完后局部变量会自动销毁。
- 当函数体内局部变量和函数体外的变量重名的话,内部局部变量将会遮盖同名的全局变量
var fx = 'fx is a good girl'
function fxFn () {
console.log(fx)
var fx = 'fx is a great girl'
console.log(fx)
fx = 'very good'
console.log(fx)
}
console.log(fx)
fxFn()
console.log(fx)
// 依次输出 1. fx is a good girl 2. undefined 3. fx is a great girl 4. very good 5.fx is a good girl
var fx = 'fx is a girl'
var fxs = 'yes'
function fxFn () {
console.log(fx) // undefined
console.log(fxs) // yes
fx = 'very good'
fxs = 'not'
console.log(fx) // very good
console.log(fxs) // not
var fx = 'fx is a great girl'
console.log(fx) // fx is a great girl
console.log(fxs) // not
}
console.log(fx) // fx is a girl
console.log(fxs) // yes
fxFn()
console.log(fx) // fx is a girl
console.log(fxs) // not
什么是作用域嵌套
当一个块或函数嵌套在另一个块或函数中时,就发生了作用域的嵌套。因此,在当前作用域中无法找到某个变量时,引擎就会在外层嵌套的作用域中继续查找,直到找到该变量,或抵达最外层的作用域(也就是全局作用域)为止。
示例
如下代码,对 b
进行的 RHS
引用无法在函数 foo
内部完成,但可以在上一级作用域(在这个例子中就 是全局作用域)中完成。
function foo (a) {
console.log(a + b);
}
var b = 2;
foo(2);
函数被调用之前作用域链已经存在
fxAge = 'fx is 18 years old'
function fxFn () {
console.log(fxAge) // undefined
var fxAge = 'fx is 8 years old'
var fxSub = 'fx is 25 years old'
console.log(fxAge) // fx is 8 years old
function fxFnSub () {
console.log(fxSub) // fx is 25 years old
console.log(fxAge) // fx is 8 years old
}
return fxFnSub;
}
var fx = fxFn()
fx()
如下代码,在函数被执行之前已经创建了两条作用域链:
- 全局作用域 ->
fxFn
函数作用域 - 全局作用域 ->
fxFnSub
函数作用域
var fx = 'fx is a great girl'
function fxFn () {
// 输出的是全局作用域的 fx:fx is a great girl
console.log(fx)
}
function fxFnSub () {
var fx = 'fx is 18 years old'
return fxFn
}
var myFx = fxFnSub()
myFx()
// x 的作用域是全局作用域,全局作用域中没有对 a 进行定义
var x = function () {
console.log(a);
};
function y(f) {
var a = 2;
f();
}
y(x) // ReferenceError: a is not defined
综上示例,可以理解为
函数的作用域与变量一样,就是其声明时所在的作用域,与其运行时所在的作用域无关。
遍历嵌套作用域链规则
引擎从当前的执行作用域开始查找变量,如果找不到, 就向上一级继续查找。当抵达最外层的全局作用域时,无论找到还是没找到,查找过程都会停止。
作用域链
如图所示,这个建筑代表程序中的嵌套作用域链。第一层楼代表当前的执行作用域,也就是你所处的位置。建筑的顶层代表全局作用域。
LHS
和 RHS
引用都会在当前楼层进行查找,如果没有找到,就会坐电梯前往上一层楼,如果还是没有找到就继续向上,以此类推。一旦抵达顶层(全局作用域),可能找到了你所需的变量,也可能没找到,但无论如何查找过程都将停止。