- From: 张立理 <otakustay@live.com>
- Date: Wed, 12 Dec 2012 07:45:33 +0000
- To: "public-html-ig-zh@w3.org" <public-html-ig-zh@w3.org>
- CC: 吕康豪 <kanghaol@oupeng.com>
- Message-ID: <COL002-W71AA002FB1B9FB1221ABC0D84F0@phx.gbl>
根据[ECMA标准第13节](http://ecma-international.org/ecma-262/5.1/#sec-13), 创建**函数定义**和**函数表达式**的过程几乎一样,唯一的区别是调用[创建函数对象](http://ecma-international.org/ecma-262/5.1/#sec-13.2)这一过程时会传递不同的**Scope**参数,**函数定义**用的是**VariableEnvironment**,**函数表达式**用的是**LexicalEnvironment**。不过现实好像有点不一样。 来看下面的代码: function test() { var x = 1; var o = { x: 2 }; with (o) { eval('function foo() { console.log(x); }'); eval('var bar = function() { console.log(x); }'); } foo(); bar(); } test(); 我没理解错的话,这段代码: - 在`with`语句外面,**VariableEnvironment**和**LexicalEnvironment**指向的是同一个对象,我这里叫它`outerEnv`。- 在`with`语句里面,会有一个新的**LexicalEnvironment**产生(是个object environment),而**VariableEnvironment**保持不变,这个新的**LexicalEnvironment**就叫它`innerEnv`。 关键的问题是,当2个`eval`调用时,这个显然是直接调用,并且不是严格模式。这种情况下,`eval`会共享外层环境的**LexicalEnvironment**和**VariableEnvironment**,因此它的代码中,**LexicalEnvironment**和**VariableEnvironment**是不同的对象,即**LexicalEnvironment**为`innerEnv`,**VariableEnvironment**是`outerEnv`。 然后在`eval`中,分别创建了一个**函数定义`foo`**和一个**函数表达式`bar`**,那么它们的`[[Scope]]`应该不一样,其中`foo`的是`outerEnv`,而`bar`的是`innerEnv`。 因此当这2个函数被执行时,`foo`应该输出`1`,`bar`输出`2`。不过事实是,Chrome、Firefox的最新版本,IE7-10,统一都是输出`2`和`2`。 同样的问题也出在`catch`语句中: function test() { var x = 1; try { throw 2; } catch (x) { eval('function foo() { console.log(x); }'); eval('var bar = function() { console.log(x); }'); } foo(); bar(); } test(); 现在的问题是,为什么ECMA要定义出一个和几乎所有浏览器(Opera和Safari等我没测,感觉八九不离十)都不同的行为。这种算是标准有问题,还是所有浏览器都应该修复呢? 其实我觉得,正常来说,**函数定义**也应该用**LexicalEnvironment**就合理了,而且**函数定义**通常是在进入函数时就被创建的,此时**LexicalEnvironment**和**VariableEnvironment**肯定是相同的,仅有`eval`配合`with`或`catch`才会出现这种情况。 Gray Zhang-------------------------------------------otakustay@live.comhttp://www.otakustay.com
Received on Wednesday, 12 December 2012 07:46:03 UTC