3

我经常发现自己需要在对象上包装一个函数以用于各种目的。是否有一种优雅的方法可以length在包装函数上保留原始函数的属性?

例如:

var x = {
    a: function(arg1, arg2) { /* do something */ }
};

function wrap(obj) {
    var original = obj.a;
    obj.a = function wrapper() {
        console.log('a called');
        original.apply(this, arguments);
    };
}

x.a.length; // => 2
wrap(x);
x.a.length; // => 0

我想做的事:

var x = {
    a: function(arg1, arg2) { /* do something */ }
};

function wrap(obj) {
    var original = obj.a;
    obj.a = function wrapper() {
        console.log('a called');
        original.apply(this, arguments);
    };
    obj.a.length = original.length;
}

x.a.length; // => 2
wrap(x);
x.a.length; // => 2 (actual still 0)

但是,这不起作用,因为length它不可写。

目前我能想到的唯一解决方案是(1)动态生成函数作为字符串和eval/new Function它或(2)有一个巨大的不同长度的代理函数数组,并选择对应于正确长度的代理函数. 这对我来说似乎不是一个优雅的解决方案,并且能够在length 指定函数中的每个参数的情况下任意创建函数似乎是一个合理的要求。

似乎bind能够在内部执行此操作:

function a(b, c) { }
a.bind(null).length; // => 2

这将创建一个具有原始长度的包装函数!这正是我希望自己能够做到的。

还有其他方法吗?

4

2 回答 2

1

我喜欢 eval(...) 方法,因为它很简单。

function wrap(obj) {
    var f = obj.fun.toString();
    f = f.replace("{", "{ alert('wrapper'); ");
    obj.fun = eval('['+f+']')[0];
}

您可以将其扩展为具有 wrap 的第二个参数,该参数表示包装器函数,并使用字符串操作来组合它们。

如果您的目标是包装的透明度,那么只需利用编程语言的动态功能。


如果您愿意对 JavaScript 文件进行额外处理,则可以内置热补丁/包装。

var x = {
    a: function(arg1, arg2) {
        (x._a || (function(){}))();
        ... do actual function stuff ...
    }
}
function wrap(obj) {
    obj._a = function() {
        console.log("ok");
    }
}
于 2012-10-24T15:58:45.890 回答
0

如果您需要以相同的方式获取已包装和未包装函数的长度,但可以不使用 length 属性来处理,这样的事情可能会有所帮助:

Function.prototype.mylengthf = function() {
    return this.mylength | this.length;
};

var x = {
    a: function(arg1, arg2) { /* do something */ },
    b: function(arg1, arg2, arg3) { /* do something else */ }
};

function wrap(obj) {
    var original = obj.a;
    obj.a = function wrapper() {
        console.log('a called');
        original.apply(this, arguments);
    };
    obj.a.mylength = original.length;
}

log(x.a.length); // => 2
wrap(x);
log(x.a.length); // => 0
log(x.a.mylengthf()); // => 2
log(x.b.mylengthf()); // => 3
​
于 2012-10-24T15:13:03.993 回答