JS 作用域
作用域:变量生效的范围;
JS
引擎执行代码时的 9
种真实作用域
Global
作用域: 全局作用域,在浏览器环境下就是window
,在node
环境下是global
Local
作用域:本地作用域,或者叫函数作用域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'
debugger
2
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