简体   繁体   中英

Is it possible to rewrite JavaScript's apply function?

I've been rewriting a lot of JavaScript's higher-order functions to get the hang of functional programming, and I'm stuck on apply . Is it possible to write apply in JavaScript? Assuming all other native functions are present, and that the ES5 spec is being used.

With ES5 and below, I don't think you can do it without using eval (see below). You can almost do it with a massive switch statment on args.length , but at some point, you just have to say there's a limit to the number of cases in that switch .

Function.prototype.newApply = function(thisArg, args) {
    switch (args.length) {
        case 0: return this.call(thisArg);
        case 1: return this.call(thisArg, args[0]);
        case 2: return this.call(thisArg, args[0], args[1]);
        // etc..
        default: throw new Error("She canna tek any more!");
    }
};

If you're allowing eval , though, you can absolutely do it — full credit to blex for suggesting eval :

Function.prototype.newApply = function(thisArg, args) {
    var f = this,
        call = "f.call(thisArg",
        i;
    for (i = 1; i < args.length; ++i) {
        call += ", args[" + i + "]";
    }
    call += ")";
    return eval(call);
};

Live Example:

 Function.prototype.newApply = function(thisArg, args) { var f = this, call = "f.call(thisArg", i; for (i = 0; i < args.length; ++i) { call += ", args[" + i + "]"; } call += ")"; return eval(call); }; var obj1 = { foo: "foo", bar: "bar" }; var obj2 = { foo: "F", bar: "B" }; function caps(o1, o2) { var k; snippet.log("this.x = " + this.x); for (k in o1) { o1[k] = o1[k].toUpperCase(); } for (k in o2) { o2[k] = o2[k].toLowerCase(); } } caps.newApply({x:42}, [obj1, obj2]); snippet.log(JSON.stringify(obj1)); snippet.log(JSON.stringify(obj2)); 
 <!-- Script provides the `snippet` object, see http://meta.stackexchange.com/a/242144/134069 --> <script src="http://tjcrowder.github.io/simple-snippets-console/snippet.js"></script> 

Or if you want to use Array#reduce :

Function.prototype.newApply = function(thisArg, args) {
    var f = this,
        call = args.reduce(function(acc, _, index) {
            return acc + ", args[" + index + "]";
        }, "f.call(thisArg") + ")";
    return eval(call);
};

You said ES5 in your question, but just for completeness: It's really easy in ES6 thanks to the spread operator ( ... ):

Function.prototype.newApply = function(thisArg, args) {
    return this.call(thisArg, ...args);
};

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM