手机版

javascript执行环境和范围的详细说明

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

最近重读了《javascript高级程序设计3》,觉得应该写一些博客,记录一些学到的知识,不然会忘得一干二净。我们今天要总结的是js的执行环境和范围。

让我们从执行环境开始。

首先是执行环境书中的概念,执行环境定义了函数可以访问的变量或其他数据,并决定了它们各自的行为。每个执行环境都有一个与之关联的变量对象。环境中定义的所有变量和函数都存储在这个对象中。虽然我们在编写代码时不能访问这个对象,但是解析器在处理数据时会在后台使用它。

执行环境是一个定义变量或函数是否可以访问其他数据的概念和机制。

在javascript中,有三种类型的可执行JavaScript代码:1。全局代码,即不在任何函数中的全局代码,如js文件、嵌入HTML页面的js代码等。2.Eval Code,即由Eval()函数动态执行的JS代码。3.函数代码,即自定义函数中函数体的JS代码。

跳过Eval Code,只谈全局执行环境和函数执行环境。

1.全球环境:

全局环境是最外层的执行环境。全局执行环境被视为窗口对象。因此,所有全局变量和函数都被创建为窗口对象的属性和方法。当代码被加载到浏览器中时,全局执行环境被创建(当我们关闭网页或浏览器时,全局执行环境被破坏)。例如,在页面中,当第一次加载JS代码时,创建一个全局执行环境。

这就是为什么闭包会有内存泄漏。因为闭包中的外部函数被视为全局环境。因此,它不会被破坏并一直保存在记忆中。

2.函数执行环境。

每个函数都有自己的执行环境。当执行到一个函数中时,该函数的执行环境将被推到执行环境堆栈的顶部,并获得执行权限。当函数被执行时,它的执行环境从栈顶被删除,执行权限返回到前一个执行环境。这是ECMAScript程序中的执行流程。

也可以解释为:当调用一个JavaScript函数时,该函数将进入该函数对应的执行环境。如果调用另一个函数,将创建一个新的执行环境,并且在函数调用期间,执行过程将在这个环境中。当被调用的函数返回时,执行过程返回到原始执行环境。因此,正在运行的JavaScript代码构成了一个执行环境堆栈。

调用函数时,创建函数的本地环境(执行函数中的代码后,环境被破坏,存储在其中的所有变量和函数定义都被破坏)。

2-1定义期间。

定义函数时,会创建[[作用域]]属性。这个对象对应一个对象列表,列表中的对象只能通过javascript内部访问,不能通过语法访问。

(范围也是范围的意思。)

我们定义一个全局函数a,函数a创建一个a的[[作用域]]属性,此时[[作用域]]只包含Global Object[全局对象]。

如果我们在A里面定义一个B函数,B函数也会创建一个[[作用域]]属性,B的[[作用域]]属性包含两个对象,一个是A的活动对象,另一个是全局对象,A的活动对象在前,而全局对象在后。

简而言之,函数的[范围]属性中对象列表的顺序是上层函数的激活对象对象,然后是上层全局对象,一直到最外面的全局对象。

下面是示例代码:a只有一个作用域,b有两个作用域。

//外部函数函数A(){ var some var;//内部函数函数B(){ var some var;}}2-2执行期。

当一个函数被执行时,它将进入该函数的执行环境。首先,它将创建自己的活动对象[激活对象](该对象包含变量对象的定义、参数、局部变量(包括命名参数)和作用域链[[作用域链]]。然后,将这个执行环境的[范围]依次复制到[[范围链]]中,最后将这个活动对象推到[[范围链]]的顶部。这样,[[作用域链]]就是一个有序的堆栈,从而确保对执行环境可以访问的所有变量和对象的有序访问。

//第一步:加载全局执行上下文和全局活动映像,创建全局执行环境。//定义全局[[范围]]。仅包含窗口对象。//扫描全局定义变量和函数对象:color【未定义】,changecolor【FD创建change color的[[范围]],此时只包含全局活动对象】,并将其添加到window中,因此全局变量和全局函数对象被定义为window的属性。//程序已经定义,所以changecolor(),color()可以在这个执行环境的任何地方执行,color也已经定义,但是它的值没有定义。//第二步是赋值‘blue’var color=‘blue’;//不需要赋值,引用自己的函数changecolor() {//第四步:进入changecolor//的执行环境将changecolor的[[作用域]]复制到作用域链//创建一个活动对象,扫描定义变量和定义函数,othercolor【undefined】和swap colors【FD】创建交换颜色的[[作用域]]并将活动对象和change color的全局活动对象连接到活动对象。同时,参数和这个应该被添加到活动对象中。//活动对象被推到范围链的顶部。//程序已经定义,所以swapcolors()可以在这个执行环境的任何地方执行,并且已经定义了othercolor,但是它的值是未定义的//第五个另一个颜色赋值“red”swap colors(),other color=“red”;//不需要赋值,只是引用自己的函数swapcolors() {//第七步:进入swapcolors的执行环境,创建其活动对象//将swapcolors的[[scope]]复制到作用域链//扫描定义变量和定义函数对象。将变量tempcolor【未定义】,参数和此添加到活动对象中。//将活动对象推到范围链的顶部。//第八步:Tempcolor赋另一种颜色,会沿着作用域链找到,继续执行var tempcolor=anothercoloranothercolor=colorcolor=tempcolor}//第六步:执行swapcolors并进入其执行环境swap colors();}//第三步,执行changecolor,进入其执行环境change color();2-3访问标识符:

在执行js代码的过程中遇到标识符时,会根据标识符的名称在Execution Context的作用域链中进行搜索。从作用域链的第一个对象(函数的Activation Object对象)开始,如果没有找到,搜索作用域链中的下一个对象,以此类推,直到找到标识符的定义。如果搜索后没有找到作用域中的最后一个对象,即全局对象,将引发错误,提示未定义。

第二,范围/范围链(Scope/Scope Chain)。

在环境中执行代码时,会创建一个范围链。范围链的目的是确保有序地访问执行环境可以访问的所有变量和函数。整个范围链是由不同执行位置的变量对象按照规则构造的链表。范围链的前端始终是当前执行代码所在环境的变量对象。

如果环境是一个函数,那么它的激活对象就是一个变量对象。活动开始时只包含一个变量,它是函数内部的参数对象。作用域链中的下一个变量对象来自函数的包含环境,而下一个变量对象来自下一个包含环境。这样,全局执行环境的变量对象总是范围链中的最后一个对象。

如图所示:

书中的例子:

var color=' bluefunction change color(){ var other color=' red ';函数swap colors(){ var tempcolor=other color;anothercolor=colorcolor=tempcolor//Todo某物} swap colors();} change color();//此处无法访问tempcolor和anocolor您可以访问颜色;警报(“颜色现在是”颜色);通过以上分析,我们可以知道内部环境可以通过范围链访问所有外部环境,但是外部环境不能访问内部环境中的任何变量和函数。

这些环境是线性有序的。每个环境都可以搜索范围链来查询变量和函数名;但是,任何环境都不能通过向下搜索范围链来进入另一个执行环境。

对于上例中的swapcolor()函数,其作用域链包括:swapcolor()变量对象、changecolor()变量对象和全局对象。swapcolor()的本地环境开始在自己的Variable Object中搜索变量和函数名,如果找不到,就向上搜索changecolor作用域链。等等。但是,changecolor()函数无法访问swapcolor中的变量。

启示:尽可能使用局部变量可以减少搜索时间。

1.没有块级范围。

与c、c和JAVA不同,Javscript没有块级作用域。请看下面的代码:

If(true){ var myvar='张三';} alert(myvar);//张三,如果有块级作用域,myvar不能从外部访问。再往下看。

for(var I=0;i10I){ console . log(I)} alert(I);//10对于具有块级作用域的语言,如java或c#代码,I作为初始化的变量,不能在的外部访问。因为I只存在于for循环的权重中,所以在运行for循环后,for循环中的所有变量都会被销毁。然而,在javascript中,情况并非如此。for中的变量声明将被添加到当前的执行环境中(这里是全局执行环境),所以在for循环结束后,变量I仍然存在于循环外的执行环境中。因此,输出10。

2.声明变量。

当使用var声明变量时,它将被自动添加到最近的可用环境中。对于函数内部,最接近的环境是函数的局部变量。如果在初始化变量时不使用var,则该变量会自动添加到全局函数中。

代码如下:

Var名称='小明';函数getName(){ alert(name);//'undefined' var name='小黄';警报(名称);//黄啸}getName()为什么名字没有定义?这是因为,当进入函数执行环境时,javascript解析器会先扫描var和function。

相当于将var或函数声明提升到执行环境的顶部。

也就是说,在输入我们的getName函数时,标识符搜索机制找到了var,搜索到的名字是局部变量名,而不是全局名,因为函数中的名字被提升到了顶部。

上面的代码将被解析如下:

Var名称='小明';函数getName(){ var name;警报(名称);//'undefined' var name='小黄';警报(名称);//黄啸}getName()扩展范围链:

虽然执行环境中只有——全局作用域和函数作用域两种,但是作用域链可以通过某种方式进行扩展。因为有些语句可以在作用域链的顶部添加一个临时变量对象。这种现象发生在两种情况下:1。try-catch语句的catch块;2.带语句;

以上就是本文的全部内容,希望对大家学习和理解javascript的执行环境和范围有所帮助。

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