【问题标题】:Change function behavior without proxy在没有代理的情况下更改功能行为
【发布时间】:2016-06-03 17:22:34
【问题描述】:

我可以这样做:

var foo = ...// some function assignment
var fooString = foo.toString()
...
// add some alert to foo
...
var fooWithAlert = new Function(forStringWithAlert)

有没有办法先改变foo 而不是创建新函数? 我需要它来修补一些依赖项,而无需重新创建整个对象层次结构。

我需要修补库中的构造函数,只需在每次调用时添加警报。但无需处理原型

【问题讨论】:

  • 你可以通过添加alert函数来操作字符串,然后将这个操作后的字符串附加到head标签中,不确定是否有其他解决方案。
  • 简化事情很好,但我认为您已经简化了这个问题,以至于您可能省略了与答案相关的细节。具体来说,您需要对foo 所指的功能做什么?你能想出一个简单但有代表性的,你需要做的事情吗?

标签: javascript monkeypatching


【解决方案1】:

不,您不能修改 foo 所指的函数。您只能使 foo 引用一个可以执行您想要的新功能。一种方法是使用您的toString 方法,但最好尽可能避免这种情况,因为您获得的功能与原始功能不同;它可以访问的范围会有所不同。

通常,您确实需要代理/包装器,例如:

// The original foo
var foo = function(arg) {
    return "original foo says '" + arg + "'";
};
console.log(foo("bar"));

// Let's wrap it
(function() {
    var originalFoo = foo;
    foo = function() {
        return originalFoo.apply(this, arguments) + " plus updated foo";
    };
})();
console.log(foo("bar"));

这不会创建对象或类似对象的层次结构,它只是包装foo

如果foo 是一个构造函数(我们称它为Foo),您还需要复制Foo.prototype

// The original Foo
var Foo = function(arg) {
    this.value = "original foo";
    this.arg = arg;
};
Foo.prototype.getArg = function() {
    return this.arg;
};
var f1 = new Foo("bar");
console.log(f1.getArg());

// Let's wrap it
(function() {
    var originalFoo = Foo;
    Foo = function() {
        var rv = originalFoo.apply(this, arguments);
        this.arg += " (plus more from augmented foo)";
        return rv;
    };
    Foo.prototype = originalFoo.prototype;
})();
var f2 = new Foo("bar");
console.log(f2.getArg());

当然,如果您需要在Foo.prototype 上包装一个函数,您可以像我的第一个示例中的foo 那样做:

// The original Foo
var Foo = function(arg) {
    this.value = "original foo";
    this.arg = arg;
};
Foo.prototype.getArg = function() {
    return this.arg;
};
var f = new Foo("bar");
console.log(f.getArg());

// Let's wrap its getArg
(function() {
    var originalGetArg = Foo.prototype.getArg;
    Foo.prototype.getArg = function() {
        return originalGetArg.apply(this, arguments) + " updated";
    };
})();
console.log(f.getArg());

请注意,我们在创建f 对象之后包装原型函数并不重要。

【讨论】:

  • 最好将originalFoo 封装在 IIFE 中?
  • 如果他想在其中添加大约 20 行代码逻辑怎么办?这种方法还能实现吗?
  • 我想我需要更具体的github.com/Jxck/assert/blob/master/assert.js#L190foo原型在这种情况下会发生什么?
  • @Reddy:是的,数量无关紧要,只是位置。 Wrappers 用于在原始文件之前、之后或两者兼而有之,但不能在中间
  • @Alnitak:我没想到 OP 会逐字使用代码,我期待的是一些常识。 :-)
猜你喜欢
  • 2021-08-13
  • 2022-07-08
  • 2019-11-09
  • 2017-03-24
  • 2018-06-20
  • 1970-01-01
  • 1970-01-01
  • 2014-07-13
  • 2014-03-08
相关资源
最近更新 更多