JS 作用域
作用域:变量生效的范围;
JS 引擎执行代码时的 9 种真实作用域
Global作用域: 全局作用域,在浏览器环境下就是window,在node环境下是globalLocal作用域:本地作用域,或者叫函数作用域Block作用域:块级作用域Script作用域:script标签中使用let、const声明的全局变量会保存在Script作用域,这些变量可以直接访问,但却不能通过window.xx访问模块作用域:其实严格来说这也是函数作用域,因为
node执行它的时候会包一层函数,算是比较特殊的函数作用域,有module、exports、require等变量Catch block作用域:catch语句的作用域可以访问错误对象With block作用域:with语句会把传入的对象的值放到单独的作用域里,这样with语句里就可以直接访问了Closure作用域:函数返回函数的时候,会把用到的外部变量保存在Closure作用域里,这样再执行的时候该有的变量都有,这就是闭包。eval的闭包比较特殊,会把所有变量都保存到Closure作用域Eval作用域:eval代码声明的变量会保存在Eval作用域
Global 作用域
浏览器环境下用 var 全局声明的变量所在的作用域—— Global作用域,也就是全局作用域
在浏览器环境下,可以通过
变量名访问全局变量,也可以通过window.变量名访问
<script lang="js">
var a = 'Global作用域'
debugger
console.log(a) // Global作用域
console.log(window.a) // Global作用域
</script>2
3
4
5
6
7
8
Local 作用域
函数内部的作用域—— Local作用域,也就是本地作用域,或者叫函数作用域
node环境下多了一种Local作用域,叫做模块作用域
<script lang="js">
function test() {
var a = 'Local作用域 a';
const b = 'Local作用域 b';
debugger
}
test()
function aa() {
var a = 'Local作用域 a';
{
var b = 'Local作用域 b'; // var 不形成块级作用域
}
debugger
}
aa()
</script>2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
Block 作用域
ES6 块语句 {} 生成的作用域—— Block作用域,也就是块级作用域
if、while、for等语句都会生成Block作用域;
var不会形成Block作用域,需要使用let const
<script lang="js">
{
var a = 'Global作用域';
const b = 'Block作用域';
debugger
}
function bb() {
const b = 'Local作用域 b';
{
var a = 'Local作用域 a';
const b = 'Block作用域 b';
const c = 'Block作用域 c';
function x() {
return 'Local作用域 x'
}
debugger
}
console.log(a) // 'Local作用域 a'
console.log(b) // 'Local作用域 b'
console.log(x()) // 'Local作用域 x'
console.log(c) // 'Uncaught ReferenceError: c is not defined'
debugger
}
bb()
</script>2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
Script 作用域
浏览器 环境下用 let const 声明全局变量时的特殊作用域—— Script作用域。可以直接访问这个全局变量,但是却不能通过 window.xx 访问
<script lang="js">
var a = 'Global作用域 a';
let b = 'Script作用域 b';
const c = 'Script作用域 c';
console.log(a) // 'Global作用域 a'
console.log(window.a) // 'Global作用域 a'
console.log(b) // 'Script作用域 b'
console.log(window.b) // undefined
console.log(c) // 'Script作用域 c'
console.log(window.c) // undefined
debugger
</script>2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
模块作用域
node 环境下就没有了 Script作用域,但是多了一个 Local作用域,Local作用域 还有 module、exports、require 等变量,这个叫做 模块作用域
也是函数作用域
var a = 'Local作用域 a'
let b = 'Local作用域 b'
const c = 'Local作用域 c'
debugger2
3
4
5
Catch block 作用域
catch 语句也会生成一个特殊的作用域—— Catch block作用域,特点是能访问错误对象
finally语句中形成正常的Block作用域
<script lang="js">
try {
throw new Error('Catch block作用域')
} catch ( e ) {
debugger
}
</script>2
3
4
5
6
7
8
在 node 中也是一样
try {
throw new Error('Catch block作用域')
} catch ( e ) {
debugger
}2
3
4
5
With block 作用域
with 语句也会生成一个特殊的作用域—— With block作用域,特点是可以直接访问 with 对象的值
语句里面再声明的变量不属于
With block作用域
<script lang="js">
with ({ c: 3 }) {
var a = 'Global作用域 a'
const b = 'Block作用域 b'
c = 'With block作用域 c' // With block作用域 的内容可直接访问
debugger
function f() {
var d = 'Local作用域 d'
const e = 'Local作用域 e'
debugger
}
}
f()
</script>2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
Closure 作用域
闭包是 JS 的常见概念,它是一个函数返回另一个函数的形式,返回的函数引用了外层函数的变量,就会以闭包的形式保存下来
通过
Closure作用域保存了使用到的变量的值,这个Closure作用域就是闭包的核心
单层闭包
只将用到的、外部作用域的变量保存到
Closure作用域
<script lang="js">
function fn() {
const a = 'Closure作用域 a';
const b = 'Local作用域 b'; // 没用到,不保存到 Closure作用域
debugger
return function () {
const c = 'Local作用域 c'; // 不是外部作用域,不保存到 Closure作用域
debugger;
console.log(a, c);
};
}
fn()()
</script>2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
多层闭包
用到的外部变量分别在不同的作用域里,那就会生成多个
Closure作用域
<script lang="js">
function fun() {
const a = 'Closure作用域 fun';
const b = 'Local作用域 b';
debugger
return function () {
const c = 'Closure作用域 c';
const d = 'Local作用域 d';
debugger;
return function () {
const e = 'Local作用域 e';
debugger
console.log(a, c, e);
};
};
}
fun()()()
</script>2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
闭包中的 eval
把所有外部的作用域的变量都保存到了
Closure作用域
node环境下会包括模块作用域的变量
<script lang="js">
function fn() {
const a = 'Closure作用域 a';
const b = 'Local作用域 b';
debugger
return function () {
const c = 'Local 作用域 c';
debugger;
eval("console.log(a, c);");
};
}
fn()()
</script>2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
node 执行中的闭包
之所以说模块作用域是特殊的函数作用域是因为与 node 模块的执行机制有关
node会把模块变为一个函数,它有 exports、require、module、__dirname、__filename 这五个参数,然后传入这五个参数来执行,模块里的函数引用模块作用域的变量,再执行,自然就形成了闭包
function func() {
require
debugger;
}
func()2
3
4
5
6
Eval 作用域
eval 的代码里声明的变量都在这个作用域里
node环境下会将模块作用域的变量放入Closure作用域
<script lang="js">
eval(`
const a = 1;
const b = 2;
const c = 3;
console.log(a,b,c);
debugger;
`);
</script>2
3
4
5
6
7
8
9
10
11