深入javascript之作用域

一,作用域

包括静态作用域和动态作用域,静态作用域也叫词法作用域,JavaScript采用的是静态作用域。

JavaScript中作用域是指可访问变量,对象,函数的集合,也就是调用它们能生效的代码区块。在JavaScript中没有块级作用域,只有全局作用域和函数作用域,可以模仿块级作用域,下面会讲到。

全局,函数作用域

看个简单的例子

1
2
3
4
5
6
7
8
9
10
11
12
13
var a = 10  
function f1(){
var b = c = 20;
console.log(a); //10
console.log(c); //20
function f2() {
console.log(b); //20
}f2();
}
f1();
console.log(a); //10
console.log(c); //20
console.log(b); //error

var b = c = 20 是指 var b = c; c = 20
在f1函数中c没使用var声明为全局变量,b为局部变量,绑定在f1函数下,外部访问不到。

模仿块级作用域

没有块级作用域,但是有if(),for()等块语句,在块语句内部定义的变量会保留在它们已经存在的作用域内,举个栗子:

1
2
3
4
5
if(true) {  
var word = 'hello';
console.log(word); //hello
}
console.log(word); //hello

f()语句存在全局作用域下,所以内部定义的变量存在于全局作用域中,无论在哪都可以访问。

1
2
3
4
5
6
7
8
9
function add(num) {  
if(num > 10) {
var num = 10;
console.log(num); //10
}
console.log(num); //10
}
add(11);
console.log(num); //Uncaught ReferenceError: num is not defined

此时if()在add函数中,内部定义的变量存在于add函数的作用域中,只有在函数和块语句中才可以访问到,外部无法访问。

使用自执行的匿名函数包裹块语句构建块作用域,也叫私有作用域

1
2
3
4
5
6
7
function add(num) {  
for(var i = 0; i < num; i++) {
console.log(i); //0,1,2,3,4,5,6,7,8,9
}
console.log(i); //10
}
add(10);

将代码改为:

1
2
3
4
5
6
7
8
9
function add(num) {  
(function () {
for(var i = 0; i < num; i++) {
console.log(i); //0,1,2,3,4,5,6,7,8,9
}
})()
console.log(i); //Uncaught ReferenceError: i is not defined
}
add(10);

此时变量i只能在for()循环中访问到,在add函数和外部都无法访问,并且在匿名函数中定义的任何变量都会在执行结束时被销毁,所以变量i只能在for()循环中使用。

在ES6中新增了块级作用域,let const声明的变量在块语句中声明时,外部无法访问。

对作用域有明确的理解对于后面学习执行上下文会有很大帮助。