javascript的做用域是一个重要的知识点,javascript做用域(scope)是经过javascript的做用域链(scope chain)来实现的。javascript
javascript做用域html
javascript做用域(scope):简单的说,就是建立一个函数时在什么环境下建立的,它控制了javascript代码运行时变量和函数的访问范围。在JavaScript中,变量的做用域有全局做用域和局部做用域两种。前端
全局做用域(Global Scope)java
在代码中任何地方都能访问到的对象拥有全局做用域,注意:全局变量是魔鬼!由于它效率低(后面讲到),污染全局环境!通常有一下三种方式获取全局做用域。浏览器
代码最外层定义的函数和变量拥有全局做用域函数
在代码的最外层,定义的函数、变量,都是拥有全局做用域的。性能
var a =1;function b(){var a =2;}b();alert(a);//1优化
函数内部不使用var定义的拥有全局做用域this
在函数内部,不使用var定义的变量拥有全局做用域,这是个坑!要注意,不少前端开发工程师不习惯写var,其实这时候你已经污染了全局做用域!htm
var a =1;function b(){ a =2; c =3;}b();alert(a);//2alert(c);//3
全部window对象的属性拥有全局做用域
在《正确理解javascript的this关键字》中我提到了脚本语言的运行须要宿主,在浏览器的全局对象是window,因此全局的变量和函数是window的属性,而且拥有全局做用域。
function a(){ window.b=1;}a();alert(b);//1
局部做用域(Local Scope)
和全局做用域相反,局部做用域通常只在固定的代码片断内可访问到,最多见的例如函数内部,全部在一些地方也会看到有人把这种做用域称为函数做用域。以下面的代码中b就是一个局部变量,在函数外部是访问不到的。
var a =function(){var b =1;alert(b);}a();alert(b);//出错 b undefined
javascript做用域链
javascript做用域(scope)是经过javascript的做用域链(scope chain)来实现的。javascript函数对象中拥有一个仅供javascript引擎访问的内部属性——[[Scope]],[[Scope]]指向一个集合,即为“做用域链(Scope chain)”,它决定了哪些数据能被函数访问。
var a =1;function fn1(){var a =9;function fn2(){alert(this.a);//1alert(a);//9} fn2();}fn1();
上面代码的做用域链,能够用下面的图来表示:
javascript的做用域链图示
做用域链与javascript代码优化
代码在运行时,变量的查找老是从做用域链的底部开始往上查找,若是第一层没找到,就要从更高一级做用域查找,这样一直找下去,一直找到全局做用域,若是没有找到则返回undefined。
从做用域链的结构能够看出,在运行期上下文的做用域链中,标识符所在的位置越深,读写速度就会越慢。由于全局变量老是存在于运行期上下文做用域链的最末端,所以在标识符解析的时候,查找全局变量是最慢的。因此,在编写代码的时候应尽可能少使用全局变量,尽量使用局部变量。
一个好的经验法则是:若是一个跨做用域的对象被引用了一次以上,则先把它存储到局部变量里再使用。以下面的代码:
function changeColor(){ document.getElementById("btnChange").onclick=function(){ document.getElementById("targetCanvas").style.backgroundColor="red";};}
这个函数引用了两次全局变量document,查找该变量必须遍历整个做用域链,直到最后在全局对象中才能找到。这段代码能够重写以下:
function changeColor(){var doc=document; doc.getElementById("btnChange").onclick=function(){ doc.getElementById("targetCanvas").style.backgroundColor="red";};}
这段代码比较简单,重写后不会显示出巨大的性能提高,可是若是程序中有大量的全局变量被从反复访问,那么重写后的代码性能会有显著改善。
做用域链的延长
当执行流进入下列任何一个语句时,做用域链将获得延长:
try-catch语句的catch块
with语句
前端添加一个变量对象。对with来讲,其变量对象中包含着指定对象的全部属性和方法所做的变量申明;对catch来讲,其变量对象中包含的是被抛出的错误对象的申明。这些标量对象都是只读的,所以在with和catch语句中申明的变量都会被添加到所在执行环境的变量对象中。
当with和catch语句结束以后,做用域链会恢复到原先的状态。
值得一提的是改变了javascript的做用域链以后,代码效率会下降。拿with语句来讲,当代码运行到with语句时,运行期上下文的做用域链临时被改变了。一个新的可变对象被建立,它包含了参数指定的对象的全部属性。这个对象将被推入做用域链的头部,这意味着函数的全部局部变量如今处于第二个做用域链对象中,所以访问代价更高了。
继续阅读关于javascript的做用域的文章:
javascript的词法做用域
正确理解javascript的this关键字
声明:文章未声明为原创文章,本文连接 http://js8.in/875.html. 转载请注明转自 JS8.IN ?