js学习170709

来源:互联网 发布:mac versions 破解版 编辑:程序博客网 时间:2024/06/10 03:15
原文:http://blog.csdn.net/guorun18/article/details/49820203

作用域:

下面我们先搞明白这样几个概念:

函数对象的[[scope]]属性、ScopeChain(作用域链)

Execution Context(运行期上下文)、Activation Object(激活对象)


[[scope]]属性:

JavaScript中每个函数都是一个函数对象(函数实例),既然是对象,就有相关的属性和方法。[[scope]]就是每个函数对象都具有的一个仅供javascript引擎内部使用的属性,该属性是一个集合(类似于链表结构),集合中保存了该函数在被创建时的作用域中的所有对象,而这个作用域集合形成的链表则被称为ScopeChain(作用域链)。

该作用域链中保存的作用域对象,就是该函数可以访问的所有数据。

例如:

function add(num1, num2){

    var sum = num1 + num2;

    return sum;

}

当add函数被创建时,函数所在的全局作用域的全局对象被放置到add函数的作用域链([[scope]]属性)中。我们可以从图1中看到作用域链的第一个对象保存的是全局对象,全局对象中保存了诸如this,window,document以及全局对象中的add函数,也就是他自己。这也就是我们可以在全局作用域下的函数中访问window(this),访问全局变量,访问函数自身的原因。当然还有函数作用域不是全局的情况,等会儿我们再讨论。


Execution Context(运行期上下文)、Activation Object(激活对象):

var total = add(5, 10);

当开始执行此函数时,就会创建一个Execution Context的内部对象,该对象定义了函数运行时的作用域环境(注意这里要和函数创建时的作用域链对象[[scope]]区分,这是两个不同的作用域链对象,这样分开我猜测一是为了保护[[scope]],二是为了方便根据不同的运行时环境控制作用域链。函数每执行一次,都会创建单独的 Execution Context,也就相当于每次执行函数前,都把函数的作用域链复制了一份到当前的Execution Context中)。Execution Context对象有自己的作用域链,在Execution Context创建时初始化,会将函数创建时的作用域链对象[[scope]]中的全部内容按照在[[scope]]作用域链中的顺序复制到 Execution Context的作用域链中。


此时,在Execution Context的作用域链的顶部会插入一个新的对象,叫做Activation Object(激活对象),这个激活对象又是干嘛的呢?这个激活对象保存了函数中的所有形参,实参,局部变量,this指针等函数执行时函数内部的数据情况,这个Activation Object是一个可变对象,里面的数据随着函数执行时的数据的变化而变化,当函数执行结束之后,就会销毁Execution Context,也就会销毁Execution Context的作用域链,当然也就会销毁Activation Object(但如果存在闭包,Activation Object就会以另外一种方式存在,这也是闭包产生的真正原因,具体的我们稍后讨论。)。函数在运行过程中,没遇到一个变量,都会去Execution Context的作用域链中从上到下依次搜索,如果在第一个作用域链(假如是Activation Object)中找到了,那么就返回这个变量,如果没有找到,那么继续向下查找,直到找到为止,这也就是为什么函数可以访问全局变量,当局部变量和全局变量同名时,会使用局部变量而不使用全局变量,以及javascript中各种看似怪异的、有趣的作用域问题的答案(你可以用这种方法来解释你以前碰到的所有作用域问题,当然,如果还是有疑问的话,非常希望你能贴出代码,我们一起讨论。)


一般情况下,一个函数的作用域链是不会在函数运行时被改变的,但有些运算符会临时改变作用域链,with和try catch的catch子句。看下面的例子:

function initUI(){


       with (document){


           var bd = body,


               links = getElementsByTagName("a"),


               i= 0,


               len = links.length;


           while(i < len){


               update(links[i++]);


           }


           getElementById("Go-btn").onclick = function(){


               start();


           };


           bd.className = "active";


       }


}


当代码执行到with时,Execution Context的作用域链被临时改变了,一个新的可变对象被插入到作用域链的顶部,这个可变对象包含了with指定的对象的所有属性。如果此时在with 中访问函数的局部变量,就会先把新插入的可变对象遍历一遍,然后才会去Activation Object中查找,直到找到为止,此时查找效率就会降低(这也是很多人说不要使用with的原因,我认为只要设法不影响性能就行了,毕竟访问with语句指定的对象的属性还是很快的,关于性能的问题大家如果想了解的话,可以关注我的下一篇博文《javascript数据访问性能》),当try catch语句中try语句块中的代码发生错误时,会自动跳入catch语句块,并且会把catch语句指定的异常对象插入到作用域链的顶端,但catch有个特点,就是catch子句执行完毕之后,作用域链都会返回到原来的状态。


闭包:

A "closure" is an expression (typically a function) that can have free varuables together with an environment that binds those variables (that "closes" the expression). —— ECMA262

“闭包”是一个表达式(一般是函数),它具有自由变量以及绑定这些变量的环境(该环境“封闭了”这个表达式)。

闭包就是能够读取其他函数内部变量的函数。

对于闭包这个经典的话题,网上的前辈高手已经做过很多详尽的解释,如果我再过多的说明,显得有些班门弄斧,不过,对于闭包,理解的角度不同,看到的面可能就不一样。

这里我们从作用域的角度来分析一下闭包产生的方式和特点。

我们都知道,闭包允许我们访问闭包函数作用域之外的作用域内的数据(说简单点就是可以闭包允许我们访问闭包函数之外的函数的数据。),这是闭包的一个非常强大的功能,很多复杂的网页应用都和这个特性有关,例如:创建封闭的命名空间、保留外部函数执行环境。


我们一起来看一个闭包的例子:

function assignEvents(){


    var id = "xdi9592";


    document.getElementById("save-btn").onclick = function(event){


        saveDocument(id);


    };


}

上例中,在onclick事件的事件处理器中引用了外部函数assignEvents的局部变量id,形成了闭包,下面我们看一下它们的作用域图示:


性能问题:

在作用域链和闭包中的性能问题主要表现在数据读写的速度上。

由于作用域链的原因,我们访问全局作用域的数据(这里为什么不说变量呢?因为不仅包括变量,还有函数,对象等其他内容)时,效率是最低的,而访问局部数据时的效率是最高的。


所以一个非常经典的解决数据访问性能问题的方案出现了:将需要访问的数据尽量的以局部数据的方式缓存起来。这样当标识符解析程序在作用域链中寻找数据时,直接就可以在作用域链的最上层找到想要的数据,效率自然就提升了。这句话可以解决很多性能问题:设置缓存,将数据保存在局部变量中

原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 我的车卖了但是买家不过户怎么办 如果买家拍了赠品但联系不上怎么办 淘宝产品处罚下架顾客退货怎么办 生源地贷款续贷密码忘了怎么办 助学贷款续贷密码忘了怎么办 京东上回收东西如果是坏的怎么办 58.同城找的工作被骗了怎么办 京东第三方买了二手机怎么办 手机无法显示百度视频的视频怎么办 如果微信被盗号朋友钱被骗怎么办 绑定银行卡的电话号码换了怎么办办 银行卡绑定的手机号空号了怎么办 微信提示绑定银行卡次数超限怎么办 手机卡太久没用被注销了怎么办 电信宽带欠费缴费后上不了网怎么办 电信宽带欠费后缴费连不上网怎么办 电脑开不了机屏亮但不开机怎么办 手机信息探探链接点开了怎么办 买的钻戒的票丢掉了怎么办 如果我过户了原来的积分怎么办? 英雄联盟安装到了一半卡住了怎么办 微信登录不上怎么办一直在转圈 lol老是忘了放装备技能怎么办 英雄联盟屏幕出现红框锁定了怎么办 钢三开局修改对电脑有用怎么办 我的世界为什么一直黑屏闪退怎么办 苹果6plus玩游戏闪退怎么办 电脑重置开机黑屏了怎么办才好? 龟头有一小块和鱼鳞一样脱皮怎么办 海盗来了赠送碎片密码忘了怎么办 王者荣耀还差几百金币买英雄怎么办 英雄联盟更新后画面突然很卡怎么办 苹果手机微信登陆没反应怎么办 谷歌商店注册短信一直验证怎么办 英雄联盟开游戏退出来进不去怎么办 忘记了路由器和网关的密码怎么办 逆战无尽塔防71关没怪了怎么办 看香的师傅要钱特别多怎么办 电商企业有收入支出没发票怎么办 洗衣液没稀释把衣服染褪色了怎么办 衣服被洗衣液洗褪色了怎么办