作用域和作用域链

作用域和作用域链的理解

作用域:函数作用域与变量作用域

函数作用域的特点:可以调用到外面的函数,但是调用不到里面的函数
变量作用域的特点:可以调用到外面的变量,但是调用不到里面的变量


变量作用域

在JavaScript中全局变量的作用域比较简单,它的作用域是全局的,在代码的任何地方都是有定义的。然而函数的参数和局部变量只在函数体内有定义。另外局部变量的优先级要高于同名的全局变量,也就是说当局部变量与全局变量重名时,局部变量会覆盖全局变量(如下面例子)。

1
2
3
4
5
6
var num = 1;	//声明一个全局变量
function foo(){
var num = 2; //声明一个局部变量
return num;
}
console.log( foo() ); //输出2

注:声明局部变量的时候一定要var,否则解释器会将变量当做对象window的属性,相当于全局变量


函数作用域

在JavaScript中变量的作用域,并非和C、Java等编程语言一样,在变量声明的代码段之外是不可见的,我们通常称为块级作用域,然而在JavaScript中使用的是函数作用域(变量在声明它们的函数体以及这个函数体嵌套的任意函数体都是有定义的)。(如下面的例子)

1
2
3
4
5
6
function func() {
console.log(num); //输出:undefined,而非报错,因为变量num在整个函数体内都是有定义的
var num = 1; //声明num 在整个函数体func内都有定义
console.log(num); //输出:1
}
func();

注:JavaScript的函数作用域是指在在函数内声明的所有变量在函数体内始终是可见的,也就是说在函数体内变量声明之前就已经可用了。

作为属性的变量:当声明一个全局变量的时候,实际上是定义了全局对象window的一个属性。

1
2
3
var num = 1;            //声明全变量num
alert(window.num) //输出:1 声明的全局变量实际上就是声明了一个window对象的属性


作用域链

1.什么是自由变量

首先认识一下什么叫做 自由变量 。如下代码中,console.log(a)要得到a变量,但是在当前的作用域中没有定义a(可对比一下b)。当前作用域没有定义的变量,这成为 自由变量 。自由变量的值如何得到 —— 向父级作用域寻找(这种说法不严谨)。

1
2
3
4
5
6
7
var a = 100
function fn() {
var b = 200
console.log(a) // 这里的a在这里就是一个自由变量
console.log(b)
}
fn()

2.什么是作用域链

如果父级也没有呢?再层层往上找,如果找到全局变量还是没有找到,那就宣告失败,这种一层一层的关系就叫做作用域链

1
2
3
4
5
6
7
8
9
10
11
12
var a = 100
function F1() {
var b = 200
function F2() {
var c = 300
console.log(a) // 自由变量,顺作用域链向父作用域找
console.log(b) // 自由变量,顺作用域链向父作用域找
console.log(c) // 本作用域的变量
}
F2()
}
F1()

3.关于自由变量的取值

这里要纠正一下第一点时候说到的自由变量是向父级作用域寻找而得到的这个说法;因为像如下的时候会产生歧义

1
2
3
4
5
6
7
8
9
10
11
var x = 10
function fn() {
console.log(x)
}
function show(f) {
var x = 20
(function() {
f() //10,而不是20
})()
}
show(fn)

在fn函数中,取自由变量x的值时,要到哪个作用域中取?—要到创建fn函数的那个作用域中取,不论fn函数要在哪里调用
所以换一种说法,自由变量要到创建这个函数的那个域作用域中去取值;注意是创建,不是调用

1
2
3
4
5
6
7
8
9
10
11
var a = 10
function fn() {
var b = 20
function bar() {
console.log(a + b) //30
}
return bar
}
var x = fn(),
b = 200
x() //bar()

fn()返回的是bar()函数,被赋值给了x,执行x(),相当于执行bar(),需要取ab的值,b的值可以直接在fn()中取出,而a取不到,则再到创建fn()的作用域中寻找,得到a = 10,所以最后结果为 30。



作用域和作用域链
https://moewang0321.github.io/2019/08/08/2019-08-08-作用域/
作者
Moe Wang
发布于
2019年8月8日
许可协议