【问题标题】:Why Javascript doesn't let a function redefine itself from within itself?为什么 Javascript 不允许函数从自身内部重新定义自身?
【发布时间】:2012-04-14 01:34:21
【问题描述】:

考虑代码:

    window.a = function(x){ 
        var r = x*2; 
        window.a =alert; // redefines itself after first call
        return r;
    }; 
    a('2 * 2 = '+a(2)); // doesn't work. it should've alerted "2 * 2 = 4"

这也不起作用:

    window.a = function(x){ 
        alert(x); 
        window.a = function(x){ // redefines itself after first call
            var r = x*2; 
            return r;   
        }
    }; 
    a('2 * 2 = '+a(2)); // doesn't work. it should've alerted "2 * 2 = 4"

这也不是:

    window.a = function(x){ alert(x); window.c = window.a; window.a = window.b; window.b = window.c; };
    window.b = function(x){ var r = x*2; window.c = window.b; window.b = window.a; window.a = window.c; return r; };
    a('2 * 2 = '+a(2)); // doesn't work. 

基本上我已经尝试了所有可能的方法,但似乎都没有完成这项工作。谁能解释一下原因?

【问题讨论】:

  • 只是出于好奇,你为什么要这么做?
  • 嗯,第一个确实对我有用(Chrome 18)
  • 在 Chrome 和 IE 中运行良好...
  • 作为一般提示:在浏览器的 JS 控制台中尝试一下。如果你这样做了,你会很快发现 JS 函数可以做你想做的事;你只需要按照正确的顺序去做。先评估var r = a(2),然后评估a('2 * 2 = ' + r)
  • 有趣的是它可以在 Chrome 中运行。它不应该(见我的回答),在 Firefox 或 Opera 中也不应该。

标签: javascript scope definition redefinition


【解决方案1】:

正在成功地重新定义了函数,只是调用它的表达式已经获取了旧的函数引用:调用表达式中发生的第一件事是定义要调用的函数被评估,参见规范的Section 11.2.3

11.2.3 函数调用

产生式 CallExpression : MemberExpression Arguments 评估如下:

  1. ref 为评估 MemberExpression 的结果。
  2. func 为 GetValue(ref)。
  3. argList 为评估 Arguments 的结果,生成参数值的内部列表(参见 11.2.4)。
  4. 如果 Type(func) 不是 Object,则抛出 TypeError 异常。
  5. 如果 IsCallable(func) 为 false,则抛出 TypeError 异常。
  6. 如果 Type(ref) 是参考,那么
      a) 如果 IsPropertyReference(ref) 为真,则
          我。让 thisValue 为 GetBase(ref)。
      b) 否则,ref 的基础是环境记录
          我。令 thisValue 为调用 GetBase(ref) 的 ImplicitThisValue 具体方法的结果。
  7. 否则,Type(ref) 不是参考。
    a) 让 thisValue 未定义。
  8. 返回在func上调用[[Call]]内部方法的结果,提供thisValue作为this值并提供列表argList 作为参数值。

第 1 步和第 2 步发生在重新定义函数之前。

解决方案当然是让事情按照你期望的顺序发生(live example | source):

window.a = function(x){ 
    var r = x*2; 
    window.a =alert; // redefines itself after first call
    return r;
}; 
var val = a(2);
a('2 * 2 = '+ val);

旁注:有趣的是your first example 在 Chrome (V8) 中工作(它也可以在 IE6 的 JScript 版本中工作;但是,JScript 有很多问题)。它不应该工作,而且在 Firefox (SpiderMonkey)、Opera (Carakan) 或 IE9 (Chakra) 中也不行。

【讨论】:

    【解决方案2】:

    JavaScript 对运算符参数的求值顺序有严格的从左到右规则。我猜这包括函数调用运算符,这意味着第一个 a 在表达式之前被评估。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-05-18
      • 1970-01-01
      • 2013-10-30
      相关资源
      最近更新 更多