在包装函数上设置长度

时间:2012-10-24 14:29:41

标签: javascript ecmascript-5

我经常发现自己需要将一个函数包装在一个对象上以用于各种目的。是否有一种优雅的方法来保留包装函数上原始函数的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)将函数动态生成为字符串并{(1}} / eval或(2)具有巨大的代理函数数组不同长度,并选择对应正确长度的代理功能。这对我来说似乎不是一个优雅的解决方案,并且似乎是一个合理的请求,能够使用任意new Function 创建一个函数,而不用指定函数中的每个参数。

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

bind

这会创建一个包含原始长度的包装函数!这正是我想要自己做的事情。

还有其他办法吗?

2 个答案:

答案 0 :(得分: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");
    }
}

答案 1 :(得分: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
​