在ES5的时候,只存在两种作用域:函数作用域和全局作用域;ES6出现后,增加了块级作用域
首先通过代码讲下ES5中的函数作用域和全局作用域理解:
<script type="text/javascript">
var a = 0;
func();
function func()
{
var b = 1;
console.log(a); //0 函数作用域中访问全局变量
console.log(b); //1
}
console.log(b); //报错 全局作用域中访问func函数作用域中的局部变量
</script>
上面代码中,有两种作用域。全局变量a存在于全局作用域中,而变量b则存在于函数func()所在的函数作用域中,也就是局部变量。
1. 当我们在函数作用域中访问变量a时,在func函数这个作用域中找不到变量a时,会继续往全局作用域找,因此在函数作用域中访问变量a时实际上是访问的全局变量a,所以console的结果是0。
2. 如果在函数func中访问不存在的变量c,在func这个函数作用域中找不到,然后继续往全局作用域找,还是找不到变量c,然后就报错。
3. 当我们在全局作用域访问func函数中的局部变量b时,由于已经处在全局这个大作用域中,再全局作用域中找不到变量b,而全局作用域又叫顶级作用域,因此无法继续往上查找,结果就是直接报错。
可以将全局作用域和函数作用域之间的关系理解为父与子,func函数作用存在于全局作用域中,相当于儿子。当儿子没有某个东西的时候,就会找父亲要,如果父亲也没有,那就报错,而父亲是不会找儿子要东西的,这个东西就是js中的变量。js在查找变量时,都是从下级作用域往上级作用域查找的,如果一直到顶级作用域(全局作用域)都没找到,则报错。
可以通过下面的图解,再详细的看下函数作用域和全局作用域的调用方式:
<script type="text/javascript">
var i = 1;
function fn1()
{
var i = 5;
var j = 20
function fn2()
{
var i = 10;
function fn3()
{
var j = 15;
console.log(i); //10
}
fn3();
console.log(i); //10
console.log(j); //20
}
fn2();
}
fn1();
console.log(i); //1
</script>
实际调用如下图所示:
ES6出现后,增加了块级作用域
A: 在es5片段中的代码:
var a = 0;
if(a < 10)
{
a++;
var b = a;
}
console.log(b); //1 b是全局变量。处于全局作用域,会成为全局对象window对象的属性
理解:以上代码,虽然b是在if代码块中定义的,但由于ES5只有全局作用域和函数作用域,没有块级作用域,而b变量不是在函数中定义的,所以b只能是全局变量。
B: es6代码片段:
let a = 0; //注意:使用'let声明的全局变量不会成为window对象的属性
if(a < 10)
{
a++;
let b = a;
}
console.log(b); //报错 b是if代码块中的变量,只在'if'代码块{}中生效。处于块级作用域。
ES6中{ }会形成一个块级作用域,所以上面代码的b处于if这个块作用域中,不属于全局作用域。
变量提升的理解:
在ES6之前,JavaScript没有块级作用域(一对花括号{}即为一个块级作用域),只有全局作用域和函数作用域。变量提升即将变量声明提升到它所在作用域的最开始的部分。上个简单的例子如:
1 2 3 4 5 6 7 8 9 10 |
|
之所以会是以上的打印结果,是由于js的变量提升,实际上上面的代码是按照以下来执行的:
1 2 3 4 5 6 7 8 9 10 11 12 |
|
函数提升的理解:
js中创建函数有两种方式:函数声明式和函数字面量式。只有函数声明才存在函数提升!如:
1 2 3 4 |
|
只所以会有以上的打印结果,是由于js中的函数提升导致代码实际上是按照以下来执行的:
1 2 3 |
|
结语:基本上就是这样,要熟练掌握的话可以多做些练习,test:
1 2 3 4 |
|
1 2 3 4 5 6 |
|