谈到作用域,我们就能想到全局变量、局部变量等名词,接下来,我讲谈谈我对作用域的理解。
ES5中,有两种作用域:函数作用域和全局作用域。
第一段代码:
vara =0; func();functionfunc(){varb =1; console.log(a);//0 函数作用域中访问全局变量console.log(b);//1} console.log(b);//报错 全局作用域中访问func函数作用域中的局部变
上面代码中,有两种作用域。全局变量a存在于全局作用域中,而变量b则存在于函数func()所在的函数作用域中,也就是局部变量。
1. 当我们在函数作用域中访问变量a时,在func函数这个作用域中找不到变量a时,会继续往全局作用域找,因此在函数作用域中访问变量a时实际上是访问的全局变量a,所以console的结果是0。
2. 如果在函数func中访问不存在的变量c,在func这个函数作用域中找不到,然后继续往全局作用域找,还是找不到变量c,然后就报错。
3. 当我们在全局作用域访问func函数中的局部变量b时,由于已经处在全局这个大作用域中,再全局作用域中找不到变量b,而全局作用域又叫顶级作用域,因此无法继续往上查找,结果就是直接报错。
我们可以将全局作用域和函数作用域之间的关系理解为父与子,func函数作用存在于全局作用域中,相当于儿子。当儿子没有某个东西的时候,就会找父亲要,如果父亲也没有,那就报错,而父亲是不会找儿子要东西的,这个东西就是js中的变量。js在查找变量时,都是从下级作用域往上级作用域查找的,如果一直到顶级作用域(全局作用域)都没找到,则报错。上面代码中的作用域,可以通过下图来加深理解:
第二段代码:
vari =1;functionfn1(){vari =5;varj =20functionfn2(){vari =10;functionfn3(){varj =15; console.log(i);//10} fn3(); console.log(i);//10console.log(j);//20} fn2(); } fn1(); console.log(i);//1
首先,我们先看下上面的代码有多少个作用域:全局作用域、fn1函数作用域、fn2函数作用域、fn3函数作用域。
然后,我们再来看一下每一次console获取的值是怎么查找的。这里我就直接用图来表示了,如果不懂可以看前面的文字描述。
我们再在控制台中印证一下上面代码的运行结果:
前面提到,es5中只有两种作用域:函数作用域和全局作用域,而es6又新增了一种作用域:块级作用域,即{ }括号形成的作用域。
es5代码片段:
vara=0;if(a<10){a++;var b =a;}console.log(b); //1 b是全局变量。处于全局作用域,会成为全局对象window对象的属性
以上代码,虽然b是在if代码块中定义的,但由于ES5只有全局作用域和函数作用域,没有块级作用域,而b变量不是在函数中定义的,所以b只能是全局变量。
es6代码片段:
leta =0;//注意:使用'let声明的全局变量不会成为window对象的属性if(a <10){ a++;letb = a;}console.log(b);//报错 b是if代码块中的变量,只在'if'代码块{}中生效。处于块级作用域。
ES6中{ }会形成一个块级作用域,所以上面代码的b处于if这个块作用域中,不属于全局作用域。