javascript

位置:IT落伍者 >> javascript >> 浏览文章

JavaScript中的[[scope]]和Scope Chain


发布日期:2023年05月20日
 
JavaScript中的[[scope]]和Scope Chain

ECMA中规定JS使用Scope Chain来实现closureScope Chain是JS中非常重要的机制JS中所有的标识符(Identifier)都是通过Scope Chain来查找值的下面的部分是关于ECMA及其实现SpiderMonkey和JScript如何用Scope Chain和[[scope]]来实现closure的

变量标识符查找

当我们在JS程序里写下像a++这样的表达式时很难想象a的值和内存地址经过了复杂的查找过程才得以确定JS的所有标识符(通常是我们自己定义的变量名)在执行时都是从Scope Chain中查找值的这也是导致JS执行速度低的原因和JS实现灵活的动态特性的基础Scope Chain是一个链表在JS执行时总是维护着Scope Chain来保证变量的可访问性或者不可访问性对于这个过程ECMA给出了很明确的描述(我翻译了一下各位将就着看)

获取Scope Chain的下一个对象如果没有对象了则转到第

调用结果()的[[HasProperty]]方法 传递Identifier作为参数

如果结果()是true Reference(引用)类型的值它的base object是结果()而它的

property name是Identifier

跳到第

返回一个Reference类型它的base object是null它的property name 是Identifier

Reference(引用)类型的值是JS引擎使用的一种数据类型它分为base object和property name两个部分假设在JS代码中有objprop这样的表达式那么解释成Reference类型base object是对象obj而property name是字符串prop

Scope Chain开始时被设为宿主对象所以在全局代码中的变量就是宿主对象的属性Scope Chain在执行时由JS引擎自动维护编译型的引擎也会创建相应的运行时环境来做此事Scope Chain一般在函数调用或者执行进入with块的时候改变

函数的执行

JS函数执行并非简单地执行函数体(Function Body)中的JS代码在此之前JS引擎会创建一个Activation Object这个对象将会被作为Scope Chain的顶端而函数的[[scope]]属性中的对象将被链接为其后续的对象([[scope]]在函数定义时被确定稍后的内容是关于[[scope]]如何定义的)这意味着Function Body中的JS代码所使用的标识符都是按照上一部分所描述的最先从Activation Object开始查找的Activation Object创建时只有一个arguments属性它不会继承Objectprototype的属性和方法接下来的变量初始化(Variable Instantiation)将函数体中变量和函数声明的结果添加到Activation Object作为属性

函数的[[scope]]属性

[[scope]]是ECMA规定的对象的私有属性理论上只有JS引擎可以访问但FireFox的几个引擎(SpiderMonkey和Rhino)提供了私有属性__parent__来访问它(所以一会我们可以看一看它)尽管所有对象都有[[Scope]]但是它只对函数对象有用

对于函数声明和匿名函数表达式来说[[scope]]就是它创建时的Scope Chain但是对于有名字的函数表达式[[scope]]顶端是一个新的JS对象(也就是继承了Objectprototype)这个对象被链到函数创建时的Scope Chain它本身有一个属性就是函数的名字这确保了函数内部的代码可以无误地访问自己的函数名进行递归

举个例子

function f()

{

return n>?n*f(n):;

}

var f=function f()

{

return n>?n*f(n):;

}

f的递归是不安全的而f的递归是安全的但是注意这仅仅是针对标准的规定而言事实上IE并没有实现这个性质

               

上一篇:DataSetToJson扩展方法

下一篇:在.Net后置cs代码中加入JS提示语句