JavaScript做用域及做用域链

做用域分为全局做用域和局部做用域,对应的变量为全局变量和局部变量函数

全局做用域是JavaScript程序执行时,系统在内存中保留一块全局变量的区域性能

局部做用域为函数执行时产生,局部变量只有在函数内部能够访问和更改,因此又叫函数级变量spa

var a = 0;
function myfunc (){
     var b = 1;
      c = 2;
}

如以上代码,a为全局变量,而b为局部变量,c的话并无用var声名就直接赋值,此为暗示全局变量,myfunc若是没有被执行的话,c就是undefined,执行myfunc函数后,c为全局变量,能够在全局做用域访问和修改,var d = e = 3; 其中e也是暗示全局变量code

能够将做用域的概念简单的理解为上图,黑色的圆圈为城墙,城里的人想要一个东西,就先在城里找,城里没有就出城找,注意不能出去以后不能再进别的城,只能一直往出走,若是最外面(全局)也没有的话,证实没有被定义,报错,元素 id not undefined,(这个是报错,和返回undefined不同);而城外的想要找对象就只能往出找,不能进城,即便城里有。对象

做用域链就是一层一层的往出走时,每一层的做用域。blog

在JavaScript的Function对象中,有一个不能被访问的内部属性,叫作[[Scope]],它里面就包含了这个函数被建立的做用域中对象的集合,也就是做用域链。ip

函数刚建立尚未被运行时,他的做用域链就被创建,做用域链的最底层必定是Global Object(全局对象),其上多是一层一层的函数做用域,也可能没有。内存

在执行函数时会产生一个名为运行期上下文的内部对象(Activation Object(活动对象)),而且加到做用域链的最上面,这里还有一个预编译的事情,写在最后。作用域

做用域链对性能是有影响的:it

举个栗子:有一天,你在家里想看蒙娜丽莎,因此你开始在家里找,没找到,因而你就在整个县城找,仍是没有,你有去了市里,省里,全国,都没有找到,最后只能出国终于在法国找到了。

这个过程就是JavaScript运行时遇到的问题,他须要一层一层的往外找,而访问全局(出国)是最慢的,在写代码是就常常会遇到这个问题,若是不注意,慢慢积累就会对性能产生很大的影响。

好比最常引用的全局变量document,若是一个函数老是用它,每次用都有遍历整个做用域链,就至关于找了一回蒙娜丽莎,因此应该避免这样,最简单的方法就是在函数内部var doc = document事先就把document找到,这样只须要找一次就能够了,就至关于把“蒙娜丽莎”画在了小本本上面,每次想看就看一眼小本本,省了屡次出国,只出去看一次,画下来就好。

除了这个方法还有其余的方法:

用with语句也能够,不过会有一个问题,with改变了做用域链,它在做用域链的最上面加了一个对象,with就好像在你想看蒙娜丽莎的时候,with就在你耳边悄悄的说“罗浮宫”,你立马就去了罗浮宫看来蒙娜丽莎,听起来是快了,可是下一次,又想看齐白石的虾了,它仍是和你说“罗浮宫”,你跑到罗浮宫,没有,就又回家开始慢慢找,效率更慢了,因此最好不要使用。

还有try catch语句,异常对象抛出语句,try catch会先运行try里面的语句,若是出现异常,就把异常的对象抛给catch,这样的话在catch语句中只运行一个函数,这样就没有局部变量的访问,做用域链的临时改变就不会影响代码。固然,前提是了解可能出现的错误。

最好仍是使用var doc = document,简单直接,干净利落

预编译:

了解函数预编译过程能够解决函数的不少问题

预编译发生在函数执行的前一刻,主要是为了提高声明

有的人是记函数声明提高大于变量提高,但我不推荐这样记,由于最好是按计算机的步骤来走,分四步

一、建立AO(活动对象)

二、找到形参和变量声明,将变量和形参做为AO属性名(变量声明提高),不赋值,值为undefined

三、实参形参相统一(将实参赋给形参)

四、在函数体里找函数声明,值赋予函数体(函数声明提高)

这就是函数的预编译过程,函数变量声明提高大是由于它走的晚,若是和变量名相同,会有覆盖

全局的预编译同理

先建立GO(==window),变量声明提高,函数声明提高

注:以上知识点为观看《高性能JavaScript》后根据其内容加上本身的理解写的,写的很差、看不懂的地方,能够去看原著

相关文章
相关标签/搜索