76

假设我有var a = function() { return 1; }. 是否可以更改aa()返回2?也许通过编辑a对象的属性,因为每个函数都是一个对象

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

4

13 回答 13

50

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

let a = function() { return 1; }
console.log(a()); // 1
    
// keep a reference
let old = a;
   
// redefine
a = function() {
  // call the original function with any arguments specified, storing the result
  const originalResult = old.apply(old, arguments);
  // add one
  return originalResult + 1;
};

console.log(a()); // 2

瞧。

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

let 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(),更改仍然适用。

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

于 2010-01-25T23:45:59.100 回答
42

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

// 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() 的调用以准备字符串以与函数构造函数一起使用并修改函数的源代码。

于 2010-01-26T23:18:17.183 回答
39

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

我不想这么说,但据我所知——而且我已经尝试过——这是做不到的。的确,函数是一个对象,因此它具有可以在对象本身上调整和覆盖的方法和属性。不幸的是,函数体不是其中之一。它没有分配给公共财产。

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

那是因为根据规范,函数体存储在[[Code]]函数对象的内部属性中,不能直接访问。

于 2014-07-02T19:28:30.480 回答
21
let a = function() { return 1; }
console.log(a()) // 1

a = function() { return 2; }
console.log(a()) // 2

从技术上讲,您正在丢失一个函数定义并用另一个函数定义替换它。

于 2010-01-25T23:37:33.073 回答
16

这个怎么样,无需重新定义函数:

var a = function() { return arguments.callee.value || 1; };
alert(a()); // => 1
a.value = 2;
alert(a()); // => 2
于 2010-01-26T00:09:51.120 回答
12

我坚持使用 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
于 2013-05-16T07:00:57.067 回答
6

所有可行的解决方案都坚持“功能包装方法”。 其中最可靠的似乎是 rplantiko 之一

这样的函数包装很容易被抽象掉。概念/模式本身可能被称为“方法修改”。它的实现肯定属于Function.prototype. 如果有一天能得到标准原型方法修饰符(如beforeafteraround和.afterThrowingafterFinally

至于前面提到的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;
  };
})();

console.log('a() ...', a()); // --> gives 2
.as-console-wrapper { min-height: 100%!important; top: 0; }

...并利用around,代码将转换为 ...

function a () { return 1; }

console.log('original a ...', a);
console.log('a() ...', a()); // 1


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

console.log('\nmodified a ...', a);
console.log('a() ...', a()); // 2
.as-console-wrapper { min-height: 100%!important; top: 0; }
<script>
(function(d){function f(a){return typeof a==e&&typeof a.call==e&&typeof a.apply==e}function g(a,b){b=null!=b&&b||null;var c=this;return f(a)&&f(c)&&function(){return a.call(b||null!=this&&this||null,c,a,arguments)}||c}var e=typeof d;Object.defineProperty(d.prototype,"around",{configurable:!0,writable:!0,value:g});Object.defineProperty(d,"around",{configurable:!0,writable:!0,value:function(a,b,c){return g.call(a,b,c)}})})(Function);
</script>

于 2014-12-17T19:40:41.163 回答
1

这是一个基于控制时间选择器的清晰示例eworld.ui www.eworldui.net

拥有一个eworld.ui无法从外部访问 JavaScript 的 TimePicker,您将找不到与这些控件相关的任何 js。那么如何向 timepicker 添加 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('visible');
    if (customFunc != "")
        eval(customFunc + "('" + selTime + "', '" + tbName + "');");
    eval(postbackFunc + "();");

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

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

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

于 2013-10-22T15:42:41.197 回答
0

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

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

于 2010-01-25T23:43:08.963 回答
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

于 2018-01-16T19:38:06.463 回答
-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
于 2021-01-18T18:36:49.477 回答
-2

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

于 2010-01-25T23:38:02.470 回答
-2

你不能稍后再定义它吗?当您想要更改时,请尝试将其重新定义为:

a = function() { return 2; }
于 2010-01-25T23:39:13.653 回答