范围是Javascript最重要的概念之一。为了更好地
学习Javascript,您需要了解Javascript范围和动作链的
工作原理。本文简要
介绍了Javascript范围和范围链,希望能帮助您了解更多关于Javascript的知识。
Javascript的范围
任何编程
语言都有范围的概念。简单地说,范围是变量和
函数的访问范围,也就是说,范围
控制变量和函数的可见性和生命周期。在Javascript中,变量的
作用范围有两种全局和局部作用域。
1。全球行动范围(全球范围)
可以在代码中任何地方访问的对象都具有全局范围,一般
情况下,几个案例具有全局范围:
(1)外部函数定义的最外层函数和变量具有全局作用域,例如:
复制代码代码如下所示:
VaR的作者
名字=溪山;
函数doSomething(){
无功blogname = ;
功能innersay(){
警报(blogname);
}
InnerSay();
}
警报(作者名字); / /山的溪流边
警报(blogname); / /
脚本错误 (做某事); / /
(innersay) / /脚本错误
(2)定义结束时的所有变量都自动声明为全局范围,如:
复制代码代码如下所示:
函数doSomething(){
VaR的作者名字=溪山;
blogname = ;
警报(作者名字);
}
Alert (blogName); / /
警报(作者名字); / /脚本错误
变blogname具有全局范围,和作者名字不能被外界访问的功能。
(3)所有窗口对象的
属性都具有全局范围。
一般来说,内置的窗口对象的属性具有全局范围,如window.name,window.location,window.top等等。
2。地方行动范围(地方范围)
在全球范围内,一般在局部范围内只有固定的代码片段可以访问最常用的功能,如内部,所有在一些地方也会看到范围为一个范围,功能,例如,下面的代码在blogname和innersay功能具有局部范围。
复制代码代码如下所示:
函数doSomething(){
无功blogname = ;
功能innersay(){
警报(blogname);
}
InnerSay();
}
警报(blogname); / /脚本错误
(innersay); / /脚本错误
范围链(范围链)
在Javascript中,函数也是对象,而事实上,所有的Javascript是一个对象,函数对象,其他物体一样,具有可访问的代码和一系列是由Javascript引擎只访问内部属性。它的一个内在特性是{ } { }的范围,由ECMA-262第三版定义。内部属性包含函数
创建作用域中的一组对象。这个集合称为函数的范围链,它决定函数可以访问哪些数据。
当一个函数被创建时,它的作用域链由可以在创建的函数的范围内访问的数据对象填充:
复制代码代码如下所示:
添加函数(num1,num2){
VaR和= num1和num2;
收起回复;
}
创建函数添加时,它将在范围链中填充一个全局对象。全局对象包含所有全局变量,如下图所示(注:
图片只列出所有变量的一部分)。
函数添加的范围将在
执行时使用:
复制代码代码如下所示:
无功总=加(5,10);
当执行此函数时,创建一个称为执行上下文的内部对象,
运行时上下文在执行该函数时定义环境。每个运行时上下文都有自己的范围链,用于标识符解析。当运行时上下文被创建时,它的作用域链被初始化为当前运行函数的{ } }所包含的对象。
这些值被复制到运行时环境在他们的
顺序出现在函数的作用域链。他们一起形成一个新的对象,称为主动对象(活动对象),该对象包含所有的局部变量,命名
参数,这个参数的
设置和功能,那么对象将被推到的范围产业链的前端,当执行环境被破坏,将会破坏活动对象。新的作用域链如下图所示:
在函数执行过程中,遇到了不可变的,都会经历一个标识符解析过程确定获取和存储数据。从作用域链头的过程,即从活动的
目标开始
搜索,
发现同一名称的标识符,如果使用此标识符对应的变量,如果没有找到继续搜索范围链上的下一个对象,如果搜索没有找到所有的对象标识符是未定义的。在函数执行过程中,每个标识符必须接受这样的搜索过程。
范围链和代码
优化 从作用域链的结构,可以看出更深的标识符,慢的读写
速度将在运行时上下文的作用域链。如上图所示,因为全局变量总是存在于运行时上下文的作用域链的末端,这是最慢的发现全局变量分析。所以,当你写代码,你应该尝试使用尽可能少的全局变量和局部变量,使用尽可能多的。一个好的经验法则是,如果在一个交叉的对象范围是指一个以上的时间,它是存储在一个局部变量一然后再次使用。例如,下面的代码:
复制代码代码如下所示:
功能换色(){
document.getelementbyid(btnchange)。Onclick =函数(){
document.getelementbyid(targetcanvas)。风格。
背景颜色为红色;
};
}
这个函数引用两个全局变量
文档,即发现变量必须遍历整个范围链,直到最终在全局对象中找到:
复制代码代码如下所示:
功能换色(){
文档;
doc.getelementbyid(btnchange)。Onclick =函数(){
doc.getelementbyid(targetcanvas)。风格。背景颜色为红色;
};
}
这个代码比较简单。重写后,它不会表现出巨大的
性能改进。但是,如果有大量的全局变量被反复访问,重写代码的性能将得到显著改善。
改变行动的链条
一个函数的执行上下文中执行时每次
都是独一无二的,所以调用同一个函数多次会造成多个运行时环境,并执行上下文将被摧毁,当函数被执行。每个运行时上下文与一个作用域链有关。在一般情况下,在运行时上下文,它的作用域链是由语句与语句只
影响。
带语句是对象避免编写重复代码的一种
快捷方式:
复制代码代码如下所示:
功能initui(){
用(文档){
var =主体,
链接= getElementsByTagName(),
我= 0,
links.length len =;
当(i){
更新(链接{ + });
}
getElementById(btninit)。Onclick =函数(){
DoSomething();
};
}
}
这里使用宽度语句避免多次写入文档,它看起来更高效,实际上会产生性能问题。
当代码运行的语句,在运行时上下文的作用域链是暂时的改变。一个新的变量创建对象,其中包含由参数指定的对象的所有属性,该对象将被推入作用域链的头,这意味着所有的函数的局部变量在第二范围链对象,所以访问成本较高。如下图:
因此,您应该避免在
程序中使用带语句,在这种情况下,可以简单地将文档存储在局部变量中,从而提高性能。
另一个catch语句将改变范围链try-catch语句。在try代码块中发生错误时,执行过程会跳到catch语句,然后将异常对象为可变对象放在范围的头。在catch代码块,所有的功能局部变量将被放置在第二范围链对象。示例代码:
复制代码代码如下所示:
尝试{
DoSomething();
} catch(前){
警报(ex.message); / /范围链的改变
}
注意,一旦catch语句完成时,作用域链返回到以前的状态。try-catch语句在代码的调试和异常
处理是非常有用的,所以这是不
推荐的,它是完全可以避免的。你可以减少catch语句的代码优化性能的影响是一个很好的模型来代表。一个错误的功能,如:
复制代码代码如下所示:
尝试{
DoSomething();
} catch(前){
HandleError(前); / /委托
处理器的
方法 }
优化代码,handleError方法是唯一的代码,在catch子句执行。此功能接收到异常对象作为参数,这样你可以更灵活地处理错误和统一。因为只有一个语句被执行,没有获得一个局部变量,作用域链的临时变化不会影响代码的性能。