Javascript passes an array of arguments using `apply ()`, but keep this link with `call ()`

I need to combine JavaScript features call()and apply()methods. The problem I am facing is that it call()keeps the correct reference to this, but sends an array of arguments, which I have as an array when I need it to be sent as arguments to a function. The method apply()sends function arguments just fine when using an array, but I don’t know how to send it the correct reference thisto which the method naturally has access call().

Below is a simplified version of the code that I have, it probably looks pretty useless, but this is a good way to get the point to:

// AN OBJECT THAT HOLDS SOME FUNCTIONS
var main = {};
main.the_number = 15;
main.some_function = function(arg1, arg2, arg3){
    // WOULD VERY MUCH LIKE THIS TO PRINT '15' TO THE SCREEN
    alert(this.the_number);
    // DO SOME STUFF WITH THE ARGUMENTS
    ... 
};
// THIS STORES FUNCTIONS FOR LATER.
//  'hub' has no direct knowledge of 'main'
var hub = {};
hub.methods = [];
hub.methods.push(main.some_function);
hub.do_methods = function(arguments_array){
    for(var i=0; i<this.methods.length; i++){
        // With this one, '15' is printed just fine, but an array holding 'i' is 
        //  just passed instead if 'i' itself
        this.methods[i].call(arguments_array);   
        // With this one, 'i' is passed as a function argument, but now the
        //  'this' reference to main is lost when calling the function 
        this.methods[i].apply(--need a reference to 'main' here--, arguments_array); 
    }
}
+5
6

? ...

method.apply(this, [args]);

:

, , :

this.methods[i].call(main);

this.methods[i].apply(main, [args]);
+7

apply call - , this.

call :

.call(main, i, j)

apply :

.apply(main, [i, j])

, :

this.methods[i].call([i]); 

[i] this this.methods[i].

, , :

this.methods[i].call(main, i);

this.methods[i], this main i.

:

this.methods[i].call(main, arguments_array);

this.methods[i], this main arguments_array .

+2

:

main.some_function = function () {
    //...
}
main.some_function.parent = main;

// now some_function.parent holds a ref to main

, , : main main.some_function:

// self-execution function the returns a function with `that` (i.e., main) in scope
main.some_function = (function(that) {
    return function() {
        alert(that.the_number);
    }
})(main);
+1

, , - . jQuery :

var bound_some_function = function(){
    return main.some_function.apply(main, arguments);
}
// ...
hub.methods.push(bound_some_function);
// ...
this.methods[i].apply(null /*whathever, has no effect*/, arguments_array);

:

function bind(fun, scope){
    return function(){
        return fun.apply(scope, arguments);
    };
}

, google " Javascript". .

+1

( ), ( );

:

/*Lets suppose we have a class "MessageReader" that has a method printMessage
 * that for some reason needs to receive the message to be printed from a function,
 * not directly a value.*/
function MessageReader() {
    this.value = "This is NOT a message and is not supposed to be readed!";
}
/*getMessage needs to return a string that will be printed!*/
MessageReader.prototype.printMessage = function(getMessage) {
    console.log(getMessage.apply(this, []));
}

function Message(value) {
    this.value = value;
}
Message.prototype.getMessage = function() {
    return this.value;
}


var myMessageReader = new MessageReader();
var myMessage1 = new Message("This is a simple message");
var myMessage2 = new Message("This is another simple message");

/*This will print the wrong message:*/
myMessageReader.printMessage(myMessage1.getMessage);

/*But this works!*/
myMessageReader.printMessage(myMessage2.getMessage.bind(myMessage2));
0

.call() .apply() this. MDN:

apply(), , call() , apply() .

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/call

, // this , , , ,

function applyOriginalThis(fn, parametersArray)
{
    var p = parametersArray;

    switch (p.length)
    {
        case 0: fn(); break;
        case 1: fn(p[0]); break;
        case 2: fn(p[0], p[1]); break;
        case 3: fn(p[0], p[1], p[2]); break;
        case 4: fn(p[0], p[1], p[2], p[3]); break;
        case 5: fn(p[0], p[1], p[2], p[3], p[4]); break;
        case 6: fn(p[0], p[1], p[2], p[3], p[4], p[5]); break;
        case 7: fn(p[0], p[1], p[2], p[3], p[4], p[5], p[6]); break;
        case 8: fn(p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7]); break;
        case 9: fn(p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7], p[8]); break;
        default: throw "Too many parameters.";
    }
}

Of course, this will only work for the number of parameters you want to support. On the bright side, functions that take an excessive amount of parameters are the smell of code . In addition, if I'm not mistaken, this type of code was used in AngularJS 1.x as a performance optimization on .apply()(now I can not find the link).

0
source

All Articles