JavaScript函数重新定义

JavaScript函数重新定义,javascript,Javascript,是否可以从JavaScript函数本身的主体中重新定义JavaScript函数。例如,我可以执行以下操作吗 function never_called_again(args) { // Do some stuff never_called_again = function (new_args) { // Do some new stuff } } 上述内容有效吗?其语义是否正确?我不想用旧函数名创建一个新的全局变量,因为我不想在全局范围内,而是从不同的对象范围内创建这种类型

是否可以从JavaScript函数本身的主体中重新定义JavaScript函数。例如,我可以执行以下操作吗

function never_called_again(args) {
  // Do some stuff
  never_called_again = function (new_args) {
    // Do some new stuff
  }
}

上述内容有效吗?其语义是否正确?我不想用旧函数名创建一个新的全局变量,因为我不想在全局范围内,而是从不同的对象范围内创建这种类型的变量,而且我不希望在这些局部范围内重新定义函数时出现名称冲突。

您的示例基本上与:

var never_called_again = function(args) {
     //do some stuff
     never_called_again = function (new_args) {
      //do some new stuff
     }
}
因为您可能知道这是可行的:

var a = 1;

function myFunction() {
     //do some stuff
     a = 2;
}

myFunction();

alert(a) //==> 2
很明显,第一个例子也适用


你是否真的想这样做是一个更开放的问题。这会使代码更难理解吗?

是的,您可以用这种方式重新定义函数

运行此:

function never_called_again(args) {
    console.log('Func 1', args);

    never_called_again = function (new_args, x) {
        console.log('Func 2', new_args, x);
    }
}

never_called_again('arg A', 'arg B');

never_called_again('arg A', 'arg B');

结果如下:

Func 1 arg A
Func 2 arg A arg B

确实可以从函数体中重新定义函数。该技术用于所谓的

// Conditional Module Pattern
var foo = (function() {
    var t;
    return function() {
        if (t) {
            return t;
        }
        t = new Date();
        return t;
    }
})();
看起来是这样的:

// Lazy Function Definition Pattern
var foo = function() {
    var t = new Date();
    foo = function() {
        return t;
    };
    return foo();
}
此函数存储第一次调用的日期,然后返回此日期

如果将其与模块模式进行比较,区别在于初始化只在第一次调用时发生,而不是在定义时发生。对于成本高昂的初始化来说,这可能是一个巨大的好处

// Conditional Module Pattern
var foo = (function() {
    var t;
    return function() {
        if (t) {
            return t;
        }
        t = new Date();
        return t;
    }
})();

是的,这是可能的,它不会创建全局函数。我在InternetExplorer6、Firefox、Chrome和。 考虑下面的代码:

  <head>
     <title>Never called again</title>
     <style type="text/css">
     </style>

     <script type="text/javascript">

          function hello()   {
             function never_called_again(args) {
                alert("Hello world " + never_called_again);
                //do some stuff
                never_called_again = function (new_args) {
                    //do some new stuff
                    alert("hello " + never_called_again);
                }
             }
             never_called_again();
             never_called_again();

          }

      </script>

  </head>
  <body onload="">

     <button onclick="hello(); never_called_again();">Call</button>
  </body>

再也没有打过电话
函数hello(){
函数永不再次调用(args){
警惕(“你好,世界”+再也不打电话了);
//做点什么
不再调用函数(新参数){
//做一些新的事情
警惕(“你好”+再也不打电话了);
}
}
再也不打电话了;
再也不打电话了;
}
呼叫
这将打印“Hello World{function code}”,第一次打印从未调用过的函数,第二次打印“Hello{changed function code}”


但是当在button的onclick上调用它时,它会抛出一个错误,表示函数未定义,清楚地表明函数已重新定义(且未全局创建)。

完全可以在第一次调用时将函数对象重新定义为您想要的任何对象

之所以可能,是因为分配评估是从右向左处理的。这意味着在执行函数时(在本例中,在调用函数时)会捕获函数的范围

这实际上意味着在执行时,正在执行的函数对象和原始函数定义实际上是两个不同的东西,这也允许重新定义原始函数。。。什么都可以

使用它的最好(也是最酷的)方法之一是创建一个本质上是它自己的工厂的函数。通过这种方式,您不必携带大量不需要使用的对象定义

例如:

d = function(type){
    switch(type.toUpperCase()){
        case 'A' :
            d = (
                    function(){
                        return {
                            name : 'A',
                            getName : function(){return this.name;}
                        };
                    }
                )();
                break;

        case 'B' :
            d = (
                function(){
                    return {
                        name : 'B',
                        getName : function(){return this.name;}
                    };
                }
            )();
            break;

        default:
            d = (
                function(){
                    return {
                        name : 'DEFAULT',
                        getName : function(){return this.name;}
                    };
                }
            )();
            break;
    }
};

console.dir(d);
d('A');
console.dir(d);
console.log(d.getName());

严格地说,不,根本不可能重新定义JavaScript函数。虽然这是一个语义问题

一个函数可能会用另一个函数覆盖其在某个范围内的引用,当另一个函数出现在第一个函数的位置时,这是一种花招。e、 g

greet_once = function() {
  console.log('Hello.');
  greet_once = function() { console.log('Can I help you?') };
};
类似地,函数在第二次调用时可能会使用封闭范围的状态来表现不同的行为(显然不是“重新定义”)

下面的示例说明了为什么上面的模式没有重新定义,因为它依赖于父范围,而父范围可能不与调用范围共享

greet_always = function() {
  greet_once = function() {
    console.log('Hello.')
    greet_once = function() { console.log('Can I help you?') }
  };
  return greet_once()
}()

greet_always()
greet_always()
被称为
greet\u always
(总是打印“Hello.”)的函数与原来分配给
greet\u once
的函数相同


我认为最接近重新定义函数的方法是重新分配其apply和call方法,这会产生一个场景,其中
myFunction.call()
不同于
myFunction()
,这很奇怪,但可以想象是有用的。

我不知道您是否可以,但这似乎不是一件好事。我显然不知道你的情况是什么,但这听起来很有可能造成混乱,难以追踪bug和难以阅读代码。我会认真思考这是否是正确的解决方案,或者你是否想后退一步,问一个让你找到答案的问题。抱歉,如果您已经考虑了所有选项。你永远不可能知道有人已经知道或不知道…这是一个合法的用途,这是一个强大的东西。人们害怕他们不知道的东西,但这并不意味着他们不好。请注意,这种技术实际上并没有重新定义函数,它改变了不再调用的函数。原始函数不一定会消失,因为(尽管您在这里没有这样做)可以创建另一个引用原始函数的变量:put
original=never\u called\u在重新分配
之前,不再调用
并且
original()
将调用原始文件…感谢链接,这非常有趣,我正在以类似的方式使用该模式以避免各种条件执行路径。这应该是正确的答案。很高兴发现有一个名字是为这种做法创造的。@galambalazs:我给了你荣誉,并且我对你没有涵盖的方面进行了扩展,使我满意。此外,我的第一个答案和主要答案与你的答案无关,这已经足够了。它不是一个社区维基。全局变量与函数重新定义无关,它们只与Lazy Func相关。定义模式,其中