开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第1天
一、作用域
1、作用域定义:作用域就是限制某个变量只能在某个区域内有效
2、作用域分类:
局部作用域;
全局作用域;
我们先来看两段代码。
例1:
var a = 'jack';
function fn() {
var a = 'frank';
}
console.log(a); //jack**在ES6中只要{ }没有和函数结合在一起,那么应该就是**
在这个例子中,函数外的a是全局变量,函数内的a是局部变量,fn函数{}包裹起来的是局部作用域,{}之外的是全局作用域,在这里console是全局打印,故a打印出来的值为jack。
例2:
var a = 'jack';
if(true) {
var a = 'frank';
}
console.log(a); //frank
在第二个例子中,{}包裹起来的也是局部作用域,{}之外的是全局作用域,但是最终打印出来的是frank,这是因为if内部定义的变量就会变为当前执行环境的变量,故而打印出来的是frank。
下面做一个概括:
- 在ES6中只要{ }没有和函数结合在一起,那么应该就是"块级作用域"
- 在块级作用域中,var定义的变量是全局变量,let定义的变量是局部变量
- 而在局部作用域也就是函数作用域中,无论是用var定义的变量还是用let定义的变量都是局部变量
- 无论是在块级作用域还是局部作用域,省略变量前面的var或者let都会变成一个全局变量
二、作用域链
定义:同名变量的声明顺序产生的变量次序
例1:
var a = 'jack';
var b = 'andy';
function fn() {
var a = 'frank';
console.log(a); //frank
console.log(b); //andy
}
fn();
console.log(a); //jack
在这里第一个console打印的变量a会顺着作用域链去寻找离他最近的变量,即 a='frank ,同理,第二个console会找到 b='andy' ,但是对于第三个console来说,第一个a以及b的定义是全局变量,而第二个a的定义是局部变量,故第三个console全局打印则会找到第一个a的声明,即 a='jack' 。
例2:
var a = 'jack';
function fn() {
console.log(a); //undefined
var a = 'andy';
console.log(a); //andy
}
fn();
在这里我们或许就会感到很奇怪,按理来说第一个console会顺着作用域链找到 a='jack' ,并打印出jack,但是却是undefined。这是因为有var关键字有 变量提升 ,第二个 a='andy' 等于已经在函数fn内已经声明了一个变量a,但是没有赋值,故一个console打印出来的是undefined,第二个打印出来的是andy。