声明后可以改变Javascript函数吗?

时间:2010-01-25 23:35:04

标签: javascript function oop

假设我有var a = function() { return 1; }。是否可以更改a以便a()返回2?也许是通过编辑a对象的属性,因为every function is an object

更新:哇,谢谢所有回复。但是,我担心我不想简单地重新分配变量,而是实际编辑现有函数。我正在考虑如何在Scala中组合partial functions来创建新的PartialFunction。我有兴趣在Javascript中编写类似的东西,并且认为现有的函数可能可以更新,而不是创建一个全新的Function对象。

14 个答案:

答案 0 :(得分:39)

你可以用javascript做各种有趣的事情,包括重新定义功能:

var a = function(){ return 1; }

alert(a()); //1

// keep a reference
var old = a;

// redefine
a = function(){
  // call the original function with any arguments specified, storing the result
  var originalResult = old.apply(old, arguments);
  // add one
  return originalResult + 1;
};
alert(a()); //2

瞧。

编辑:更新以在更疯狂的场景中显示:

var test = new String("123");
console.log(test.toString()); // logs 123
console.log(test.substring(0)); // logs 123
String.prototype.substring = function(){ return "hahanope"; }
console.log(test.substring(0)); // logs hahanope

你可以在这里看到,即使首先定义了“test”,然后我们重新定义了substring(),但更改仍然适用。

旁注:如果你这样做,你真的应该重新考虑你的架构......当他/她正在研究一个假定的功能定义时,你会混淆一些可怜的开发人员5年后的废话返回1,但似乎总是返回2 ....

答案 1 :(得分:39)

我使用类似这样的东西来修改我无法访问其声明的现有函数:

// declare function foo
var foo = function (a) { alert(a); };

// modify function foo
foo = new Function (
  "a",
  foo.toSource()
    .replace("alert(a)", "alert('function modified - ' + a)")
    .replace(/^function[^{]+{/i,"")  // remove everything up to and including the first curly bracket
    .replace(/}[^}]*$/i, "")  // remove last curly bracket and everything after<br>
);

您可以使用toString()来获取包含函数声明的字符串,而不是toSource()。有些调用replace()来准备字符串以便与Function Constructor一起使用并修改函数的源。

答案 2 :(得分:22)

var a = function() { return 1; }
alert(a()) // 1
a = function() { return 2; }
alert(a()) // 2

从技术上讲,你失去了一个功能定义并将其替换为另一个功能定义。

答案 3 :(得分:15)

如何,无需重新定义功能:

var a = function() { return arguments.callee.value || 1; };
alert(a()); // => 1
a.value = 2;
alert(a()); // => 2

答案 4 :(得分:15)

因此,您希望直接修改函数的代码,而不仅仅是将其他函数重新分配给现有变量。

我不想这么说,但据我能说出来 - 而且我已经尝试过 - 它无法完成。确实,函数是一个对象,因此它具有可以在对象本身上进行调整和覆盖的方法和属性。不幸的是,功能体不是其中之一。它没有分配给公共财产。

documentation on MDN列出了函数对象的属性和方法。它们都没有让我们有机会从外部操纵函数体。

那是因为according to the spec,函数体存储在函数对象的内部[[Code]]属性中,无法直接访问。

答案 5 :(得分:10)

我坚持使用jvenema的解决方案,其中我不喜欢全局变量“old”。将旧函数保留在新函数中似乎更好:

function a() { return 1; }

// redefine
a = (function(){
  var _a = a;
  return function() {
  // You may reuse the original function ...
  // Typical case: Conditionally use old/new behaviour
    var originalResult = _a.apply(this, arguments);
  // ... and modify the logic in any way
    return originalResult + 1;
    }
})();
a()  // --> gives 2

答案 6 :(得分:3)

所有可行的解决方案都坚持“功能包装方法”。 The most reliable amongst them seems to be the one of rplantiko

这种功能包装很容易被抽象掉。概念/模式 本身可能被称为“方法修改”。它的实施肯定 属于Function.prototype。得到支持会很高兴 有一天通过标准的原型方法修饰符,如beforeafteraroundafterThrowingafterFinally

关于rplantiko的上述例子......

function a () { return 1; }

// redefine
a = (function () {
  var _a = a;
  return function () {
    // You may reuse the original function ...
    // Typical case: Conditionally use old/new behaviour
    var originalResult = _a.apply(this, arguments);
    // ... and modify the logic in any way
    return originalResult + 1;
  };
})();

a(); // --> gives 2

...并且使用[around],代码将转换为...

function a () { return 1; }

console.log("a : ", a);
console.log("a() : ", a());


a = a.around(function (proceed, interceptor, args) {
  return (proceed() + 1);
});

console.log("a : ", a);
console.log("a() : ", a());

答案 7 :(得分:0)

你能不能在以后再次定义它?如果您想要更改,请尝试将其重新定义为:

a = function() { return 2; }

答案 8 :(得分:0)

如果您正在调试javascript并希望了解代码的更改如何影响页面,您可以使用此Firefox扩展来查看/更改javascripts:

执行JS firefox扩展: https://addons.mozilla.org/en-US/firefox/addon/1729

答案 9 :(得分:0)

这是基于控件时间戳eworld.ui清除示例 www.eworldui.net

如果TimePicker eworld.ui无法从外部访问JavaScript,则无法找到与这些控件相关的任何js。那么如何在时间戳中添加onchange事件呢?

当您在控件为您提供的所有选项之间js时,会调用Select函数。此功能是:TimePicker_Up_SelectTime

首先,你必须复制这个函数内的代码。

...评估... quikwatch TimePicker_Up_SelectTime.toString()

function TimePicker_Up_SelectTime(tbName, lblName, divName, selTime, enableHide, postbackFunc, customFunc) {
    document.getElementById(tbName).value = selTime;
    if(lblName != '')
    document.getElementById(lblName).innerHTML = selTime;
    document.getElementById(divName).style.visibility = 'hidden';
    if(enableHide)
    TimePicker_Up_ShowHideDDL('visible');
    if(customFunc != "")
    eval(customFunc + "('" + selTime + "', '" + tbName + "');");
    eval(postbackFunc + "();");

}

现在

使用您保存的代码,然后重新分配相同的源代码,但添加您想要的任何内容..

TimePicker_Up_SelectTime = function(tbName,lblName,divName,selTime,enableHide,postbackFunc,customFunc){         document.getElementById(tbName).value = selTime;         if(lblName!='')             document.getElementById(lblName).innerHTML = selTime;         document.getElementById(divName).style.visibility ='hidden';         if(enableHide)             TimePicker_Up_ShowHideDDL( '可见');         if(customFunc!=“”)             eval(customFunc +“('”“+ selTime +”','“+ tbName +”');“);         eval(postbackFunc +“();”);

  >>>>>>>  My function  >>>>>   RaiseChange(tbName);
}

我已将My Function添加到该函数中,所以现在我可以在选择时间时模拟onchange事件。

RaiseChange(...)可以是你想要的任何东西。

答案 10 :(得分:0)

您可以更改其他对象的功能

var a1 = function(){return 1;}
var b1 = a1;
a1 = function(){
  return b1() + 1;
};
console.log(a1()); // return 2

// OR:
function a2(){return 1;}
var b2 = a2;
a2 = function(){
  return b2() + 1;
};
console.log(a2()); // return 2

答案 11 :(得分:-1)

绝对。只需为其分配一个新功能。

答案 12 :(得分:-1)

                    function get_func(func) {//from StackOverflow
                        //var args = Array.prototype.slice.call(arguments);
                        var STRIP_COMMENTS = /((\/\/.*$)|(\/\*[\s\S]*?\*\/))/mg;
                        var ARGUMENT_NAMES = /([^\s,]+)/g;
                      var fnStr = func.toString().replace(STRIP_COMMENTS, '');
                      var args = fnStr.slice(fnStr.indexOf('(')+1, fnStr.indexOf(')')).match(ARGUMENT_NAMES);
                      //var code = func.toString().match(/function[^{]+\{([\s\S]*)\}$/)[1];
                      var code =fnStr.slice(fnStr.indexOf("{") + 1, fnStr.lastIndexOf("}"));
                        var func_full_name=fnStr.substr(0,  fnStr.indexOf('{') );
                        var func_name=fnStr.slice(9, fnStr.indexOf('('));
                        if(args === null){ args = []; }
                      return { func_name:func_name,func_full_name:func_full_name, code:code, args:args};
                    }
                    function str_trim(str){
                        //replaces multi-line characters
                        return str.replace(/\n/g,'').replace(/^ +| +$/gm, '').trim();
                    }
                    function edit_func(func,callback){
                        var a_func=get_func(func);
                        var lines = a_func.code.split('\n');
                        var output=[];
                        for(var i=0;i<lines.length;i++){
                            var code=str_trim(lines[i]);
                            if(code!=''){
                                code =callback(code,output.length,a_func.args);
                                output.push(code);
                            }
                        }
                        //var test=Function(['a','b'],'alert(a);alert(b);');
                        //test(1,2);
                        //func=Function(a_func.args,output.join('\n'));
                        //return func;
                         var head = document.getElementsByTagName('head')[0];
                         var script = document.createElement('script');
                         script.type = 'text/javascript';
                        script.text =a_func.func_full_name+'{'+ output.join('\n') + '}'  ;
                        head.appendChild(script);
                    }
                    function test(id) {
                         var x, y;
                         x = 5;
                         y = 10;
                         alert(x + y);
                         alert(id);
                     }
                     edit_func(test,function(code,line,args){
                        if(line==3){
                            return 'alert(x*y);';
                        }
                        return code;
                    });
                        test(3);

尝试这个它将使用回调更改原始函数,使用回调来检查每行代码。

答案 13 :(得分:-1)

const createFunction = function (defaultRealization) {
  let realization = defaultRealization;

  const youFunction = function (...args) {
    return realization(...args);
  };
  youFunction.alterRealization = function (fn) {
    realization = fn;
  };

  return youFunction;
}

const myFunction = createFunction(function () { return 1; });
console.log(myFunction()); // 1

myFunction.alterRealization(function () { return 2; });
console.log(myFunction()); // 2