2013-12-21 28 views
2

sec 10.4.3变量/词汇环境

说,当控制进入执行 上下文中包含的功能对象楼提供thisArg呼叫者 功能代码,并提供argumentsList呼叫者执行下面的步骤:

  1. 如果功能代码是严格代码,请将ThisBinding设置为thisArg。
  2. 否则,如果thisArg为null或未定义,请将ThisBinding设置为全局对象。
  3. 否则,如果Type(thisArg)不是Object,请将ThisBinding设置为ToObject(thisArg)。
  4. 否则将ThisBinding设置为thisArg。
  5. 让localEnv是调用NewDeclarativeEnvironment传递F的[[Scope]]内部属性值作为 参数的结果。
  6. 将LexicalEnvironment设置为localEnv。
  7. 将VariableEnvironment设置为localEnv。
  8. 设代码为F的[[Code]]内部属性的值。
  9. 使用10.5中描述的功能代码和argumentsList执行声明绑定实例化。

考虑下面的代码片段:

function foo(){ 
    var a={p:'p'}; 
    o={c:'c'}; 
} 

因此,我们有以下几点:

我们的函数的
  1. 码心不是一个严格的代码
  2. thisArg为空,因此,ThisBinding设置为全局对象
  3. ---
  4. ---
  5. 我不明白什么绑定将包含environment record代表[[Scope]]代表内部财产。
  6. 设置LexicalEnvironment到geted在步骤5.
  7. 环境设置VariableEnvironment到在步骤5
  8. geted执行声明绑定instatiation环境。

在步骤8在VariableEnvironment中创建绑定,但不在LexicalEnvironment中创建绑定。但在sec 10.3说,

当一个执行上下文中创建了LexicalEnvironment和 VariableEnvironment组件最初具有相同的值。

问:

为什么刚过执行上下文LexicalEnvironment和VariableEnvironment的创作仍然在我上面的情况一样的吗?

+0

我不确定我是否理解这个问题。 'LexicalEnvironment'和'VariableEnvironment'获得在6和7中分配的相同值。 –

+0

@Felix Kling在上下文创建步骤8中,代码中声明的变量和函数将作为VariableEnvironment的环境记录中的绑定添加。但是词汇环境呢?在第8步将此绑定添加到LexicalEnvironment中吗?在我的具体情况下,函数的[[范围]]内部属性是什么? –

+0

这是一个很好的问题。我会假设它与对象类似:LexicalEnvironment和VariableEnvironment指向相同的环境,因此通过这两个组件都可以看到对该环境所做的任何更改。在你的例子中,'[[Scope]]'会引用全局执行上下文的词法环境,因为你在全局范围中定义了这个函数。请参阅http://www.ecma-international.org/ecma-262/5.1/#sec-13 –

回答

2

我不知道我理解你的问题,但是这是我的理解秒10.4.3:

步骤1到4正在处理这个值。基本上,在严格模式下,this将保留为nullundefined值,而不是默认为全局对象(浏览器为window)。这涵盖了通过通常的对象或事件处理机制不调用函数的情况。

第5步到第7步表示每次输入函数时都会创建一个新的命名环境。 它描述了这个环境的创建,它与前一个链接以形成当前的名称范围。

对于每个新功能,两个环境是共存的。 解析名称后,首先搜索词法环境,然后搜索变量环境。如果两个搜索均失败,则会在环境链的上层重复该过程,直到遇到“全部捕获”全局作用域。在此范围内,所有标识符均作为全局(window)对象的属性进行处理。您可以将其视为封闭在with (window)块中的整个代码。

词法环境可以看作是变量作用域的临时增强。 词法和可变环境是功能上相同,直到您改变两个特定语句的词法环境:withcatch。这并不意味着它们被实现为相同的数据结构。

在实现方面,您可以将词法环境想象成一个空列表,并将变量环境想象为包含所有局部变量和参数名称的列表。 当遇到catchwith语句时,词法列表将填充新的名称,该名称将优先于存储在变量列表中的名称。

catch将简单地使其参数可用于名称解析(即允许您引用异常参数)。没有什么大不了的,因为新名称与函数参数一样明确。

with是一个相当危险的野兽。它将创建一个新的环境,其中包含作为参数传递的对象的所有属性的名称。范围将由变量链环境加上这个新的词汇环境组成。 这里可用于解析的新名称在对象内部是“隐藏的”。 例如:

var a = 'a', b = 'surprise!', o = {a:'a'}; 
with (o) { a = b; } 
console.log (a+" "+b+" "+o.a); 

将产生

a surprise! surprise! 

a因为o包含一个名为a属性被解析为o.ab词汇环境中找不到,因此当前变量环境被尝试并且发现变量'b'。 这是一个非常危险的机制,因为如果您认为某个对象包含给定的属性而实际上没有,那么您将改为在当前范围外引用一个变量。 举例来说,一个简单的拼写错误这样的:

with (element.style) {leftt = '10px';} 

window.leftt属性设置为'10px',除非你已经声明了一个在当前范围内命名leftt某处变量。

现在,如果您为对象属性给出'i'或'j'等愚蠢的名称,那么您可能会在作用域链上某处打破随机循环索引,同时相信您正在设置对象的属性。

步骤8描述了一旦建立了功能范围,参数绑定。基本上,参数与值绑定在一起,并且它们的名称被添加到变量环境中。

保持两个独立的环境的全部要点在于起升机构总是使用可变环境链作为范围。

这个想法是,一个变量或函数应该像在当前作用域块的顶部声明一样工作,所以例如一个在块内声明的函数不应该使用公开的对象属性来解析其名称有声明。

坦率地说,这是一个相当有争议的问题,因为ECMA规范不允许块内部的函数声明,尽管大多数实现都使用varry结果。

现在对于你的例子:

function foo(){ 
    var a={p:'p'}; 
    o={c:'c'}; 
} 

你的函数不包含任何withcatch语句,所以里面的作用域链“富()”只是一个不变量环境的列表:

global (a bunch of DOM objects all seen as properties of 'window') 
    function foo (var a) 

一旦你调用foo(),

  • a将作为foo的局部变量解析,将创建为值为'p'的属性p的对象(并且只要您离开foo(),就立即收集垃圾,除非您设法从持久变量中引用它)。

  • o将不会在foo的变量环境中找到,所以它将被“全部捕获”全局作用域捕获,因此被解析为window对象的(新)属性。它将创建一个值为'c'window.o.c财产。

这是否对您的问题有所回答?

+0

超级有用的答案一般用于理解词法和可变环境之间的区别:) –