JS-JavaScript 的作用域

作用域(scope),是指变量的生命周期(一个变量在哪些范围内保持一定值)。

  1. 全局作用域
  2. 函数作用域
  3. 块级作用域
  4. 词法作用域
  5. 动态作用域 动态作用域跟 this 引用机制相关

全局作用域

1
2
3
4
全局变量:
生命周期将存在于整个程序之内。
能被程序中任何函数或者方法访问。
在 JavaScript 内默认是可以被修改的。
  1. 显式声明:
    带有关键字 var 的声明。
  2. 隐式声明:
    不带有声明关键字的变量,JS 会默认帮你声明一个全局变量!!!

函数作用域:

函数作用域内,对外是封闭的,从外层的作用域无法直接访问函数内部的作用域!!!

1
2
3
4
5
function bar() {
var testValue = 'inner';
}

console.log(testValue); // 报错:ReferenceError: testValue is not defined

块级作用域:

  1. ES6 之前,是没有块级作用域的概念的。
1
2
3
4
5
for(var i = 0; i < 5; i++) {
// ...
}

console.log(i); // 5

var 关键字声明的变量,在 for 循环之后仍然被保存这个作用域里。

  1. 如果想要实现 块级作用域 那么我们需要用 let 关键字声明!!!
1
2
3
4
5
for(let i = 0; i < 5; i++) {
// ...
}

console.log(i); // 报错:ReferenceError: i is not defined

for 循环执行完毕之后 i 变量就被释放了,它已经消失了!!!

  1. 同样能形成块级作用域的还有 const 关键字:
1
2
3
4
5
if (true) {
const a = 'inner';
}

console.log(a); // 报错:ReferenceError: a is not defined

letconst 关键字,创建块级作用域的条件是必须有一个 { } 包裹。

词法作用域:

当我们要使用声明的变量时:JS引擎总会从最近的一个域,向外层域查找。

1
2
3
4
5
6
7
8
9
10
11
12
13
var testValue = 'outer';

function foo() {
console.log(testValue); // "outer"
}

function bar() {
var testValue = 'inner';

foo();
}

bar();

当 JS 引擎查找这个变量时,发现全局的 testValue 离得更近一些,这恰好和 动态作用域 相反。

动态作用域:

1
2
动态作用域,作用域是基于调用栈的,而不是代码中的作用域嵌套;
作用域嵌套,有词法作用域一样的特性,查找变量时,总是寻找最近的作用域;

同样是,词法作用域,同一份代码,如果是,动态作用域:

1
2
3
4
5
6
7
8
9
10
11
12
13
var testValue = 'outer';

function foo() {
console.log(testValue); // "inner"
}

function bar() {
var testValue = 'inner';

foo();
}

bar();

参考文献