什么是作用域

作用域指的是变量存在的范围。

  • 在 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

综上示例,可以理解为

函数的作用域与变量一样,就是其声明时所在的作用域,与其运行时所在的作用域无关。

遍历嵌套作用域链规则

引擎从当前的执行作用域开始查找变量,如果找不到, 就向上一级继续查找。当抵达最外层的全局作用域时,无论找到还是没找到,查找过程都会停止。

作用域链

如图所示,这个建筑代表程序中的嵌套作用域链。第一层楼代表当前的执行作用域,也就是你所处的位置。建筑的顶层代表全局作用域。


javaScript作用域以及作用域链_作用域

​LHS​​​ 和 ​​RHS​​ 引用都会在当前楼层进行查找,如果没有找到,就会坐电梯前往上一层楼,如果还是没有找到就继续向上,以此类推。一旦抵达顶层(全局作用域),可能找到了你所需的变量,也可能没找到,但无论如何查找过程都将停止。