手机版

谈谈JavaScript范围和范围链

时间:2021-11-01 来源:互联网 编辑:宝哥软件园 浏览:

在每种编程语言中,其变量都有一定的有效范围。超过这个范围后,变量无效,这就是变量的范围。从数学的角度来看,它是自变量的领域。

范围是变量的可访问范围,即范围控制变量和函数的可见性和生命周期。在JavaScript中,对象和函数也是变量,变量在声明它们的函数体和嵌套在这个函数体中的任何函数体中定义。

1.静态范围和动态范围。

静态范围

这意味着声明的范围是在编译时根据程序文本确定的,也称为词法范围。大多数现代编程语言都采用静态范围规则,JavaScript就是这样的范围。在具有静态作用域的语言中,它基本上是最里面的嵌套作用域规则:声明引入的标识符在声明所在的作用域中是可见的,在嵌套在其中的每个作用域中也是可见的,除非它被另一个同名的声明所隐藏。为了找到给定标识符引用的对象,应该在当前最里面的范围内搜索它。如果找到声明,也可以找到标识符引用的对象。否则,我们将查看直接外部范围,并继续按顺序向外检查外部范围,直到到达程序的最外层嵌套层,即全局对象声明所在的范围。如果在所有级别都找不到声明,则程序有错误。如下所示:

函数cha(){ var name=' Xiao;'function CHB(){ function chc(){ console . log(name);}}}首先,函数从chb()中搜索名称的定义,然后继续逐层向上搜索。最后,名称的定义可以在cha()中找到。如果没有找到,将报告一个错误。

2.动态范围。

在动态范围语言中,程序中变量引用的对象是根据程序运行时的控制流信息确定的。

第二,JavaScript的范围。

JavaScript中有两种作用域,分别是全局作用域和局部作用域。

1.全球范围。

代码中的任何地方都有定义。即使在嵌套在html页面中的一段js代码中定义了一个全局变量,它仍然可以在引用的js文件中被访问。这很可能造成全局变量的污染。

以下三种情况的变量将被视为全局变量:(1)最外层的函数和变量具有全局范围;(2)未定义和直接赋值的变量被自动声明为具有全局作用域;(3)所有窗口对象的属性都具有全局范围。

2.本地范围。

局部作用域只能在固定的代码片段中访问,例如函数内部的变量(函数作用域)。

var name='许小平';函数EcHoname(){ var first name=' Xu ';//本地作用域secondname=' xiao//全局作用域函数echo first name(){ console . log(first name);//Xu } console . log(second name);返回回声名字;}console.log(名称);//全局范围var f=echo name();f();console.log(名字);console . log(second name);结果是:xuxiaopingxixu///内部函数可以访问外部函数的undefined变量//函数的内部变量xiao不能在函数外部访问。

JavaScript将全局变量附加到窗口对象,并成为窗口对象的属性。

3.功能范围。

块范围:任何一对花括号中的语句集都属于一个块,其中定义的所有变量在代码块之外都是不可见的。大多数类似C的语言都有块级的作用域。然而,JavaScript的一个重要特性是它没有块级作用域。

函数echoi(){ for(var I=0;i10I){;//console . log(I);} if(true){ var str=' hello ';} console . log(I);console . log(str);} echo I();输出结果是:

你好

可以看到,我在块中定义的变量仍然可以在for语句之外访问(或者if,while)。也就是说,JavaScript不支持块级作用域,它只支持函数作用域,函数中任何地方定义的变量在函数的任何地方都是可见的。作为一个从编程开始就学习C和java的人,这有点难以适应。根据我的测试,PHP也是这样的。

当然,您可以使用JavaScript闭包的特性来模拟块级范围。

function echoi(){(function(){ for(var I=0;i10I){;//console . log(I);} })();if(true){ var str=' hello ';} console . log(I);console . log(str);} echo I();结果是:未定义。

这隔离了变量的定义。在js中,为了防止命名冲突,应该尽可能避免全局变量和全局函数,所以这种闭包特别有用。

4.JavaScript变量的生命周期。

JavaScript变量的生命周期在声明时被初始化。局部变量在函数执行后被销毁。全局变量在页面关闭后被销毁。

第三,JavaScript的范围链。

当您查看链时,您可能可以将它与数据结构中的链表组合在一起。

在JavaScript中,函数也是对象。事实上,JavaScript中的一切都是对象。像其他对象一样,函数具有可以通过代码访问的属性和一系列只能由JavaScript引擎访问的内部属性。内部属性之一是[[范围]],由第三版ECMA-262标准定义。该内部属性包含创建函数的范围内的一组对象。这个集合被称为函数的作用域链,它决定了函数可以访问哪些数据。

当一个函数被创建时,它的作用域链将在创建该函数的作用域中被可访问的数据对象填充。例如,定义以下函数:

函数add(num1,num 2){ var sum=num 1 num 2;返回总和;}创建函数add时,其作用域链将填充一个全局对象,该对象包含所有全局变量,如下图所示(注:图片仅举例说明了部分变量):

add函数的作用域将在执行过程中使用。例如,执行以下代码:

var total=add(5,10);

执行该函数时,会创建一个名为“执行上下文”的内部对象,该对象定义了函数执行时的环境。每个运行时上下文都有自己的标识符解析范围链。创建运行时上下文时,其范围链被初始化为当前运行函数的[[范围]]中包含的对象。

这些值按照它们在函数中出现的顺序复制到运行时上下文的范围链中。它们一起组成了一个新的对象,叫做“激活对象”,包含了函数的所有局部变量、命名参数、参数集和这个,然后这个对象会被推到作用域链的前面。当运行时上下文被销毁时,活动对象也将被销毁。下图显示了新的范围链:

在函数执行过程中,每次遇到一个变量,都会经过一个标识符解析过程,决定在哪里获取和存储数据。这个过程从作用域链的头开始,即从活动对象开始,并搜索同名的标识符。如果找到,则使用对应于该标识符的变量。如果没有找到作用域链中的下一个对象,如果搜索后没有找到所有对象,则认为标识符未定义。在函数执行期间,每个标识符都必须经过这样的搜索过程。

第四,范围链和代码优化。

从作用域链的结构可以看出,标识符在运行时上下文的作用域链中越深,读写速度就会越慢。如上图所示,因为全局变量总是存在于运行时上下文范围链的末端,所以在解析标识符时找到全局变量是最慢的。因此,在编写代码时,我们应该使用尽可能少的全局变量和尽可能多的局部变量。一个很好的经验法则是,如果一个跨范围对象被引用了不止一次,那么它应该在被使用之前被存储在局部变量中。例如,以下代码:

function change color(){ document . getelementbyid(' btnChange ')。onclick=function(){ document . getelementbyid(' targetCanvas '). style . background color=' red ';};}此函数引用全局变量文档两次。要找到这个变量,您必须遍历整个范围链,直到它最终在全局对象中找到。这段代码可以改写如下:

函数ChangeColor(){ var doc=document;doc.getElementById('btnChange ')。onclick=function(){ doc . getelementbyid(' targetCanvas '). style . background color=' red ';};}这段代码比较简单,重写后不会表现出很大的性能提升,但是如果从中反复访问程序中的大量全局变量,重写后的代码性能会有明显的提升。

动词(verb的缩写)随着范围链的变化。

每个执行对应的运行时上下文是唯一的,因此对同一个函数的多次调用将导致多个运行时上下文的创建。当函数被执行时,执行上下文将被销毁。每个运行时上下文都与一个范围链相关联。一般来说,运行时上下文的范围链只会受到with语句和catch语句的影响。

with语句是一个快速的对象应用程序,可以避免编写重复的代码。例如:

函数initUI(){ with(document){ var BD=body,links=getElementsByTagName('a '),i=0,len=links.lengthwhile(I len){ update(link[I]);} getElementById('btnInit ')。onclick=function(){ dosometing();};}}在这里,width语句是用来避免多次写文档的,这样看起来效率更高,实际上会造成性能问题。

当代码运行到with语句时,运行时上下文的范围链会临时更改。将创建一个新的变量对象,其中包含参数指定的对象的所有属性。这个对象将被推入作用域链的头部,这意味着函数的所有局部变量现在都在第二个作用域链对象中,因此访问成本更高。如下图所示:

因此,在程序中应该避免with语句。在本例中,简单地将文档存储在局部变量中可以提高性能。

摘要

1.变量的范围是变量有效的范围。2.变量的作用域链是创建的作用域中的一组对象。

以上就是本文的全部内容,希望对大家学习javascript编程有所帮助。

版权声明:谈谈JavaScript范围和范围链是由宝哥软件园云端程序自动收集整理而来。如果本文侵犯了你的权益,请联系本站底部QQ或者邮箱删除。