Search code examples
javascriptapplyexecutionscoping

Confused about execution context in JS


// Replace the method named m of the object o with a version that logs
// messages before and after invoking the original method.
function trace(o, m) {

  // Remember original method in the closure
  var original = o[m];

  // Define the new method
  o[m] = function() { 

    // Log message
    console.log(new Date(), "Entering:", m);

     // Invoke original
    var result = original.apply(this, arguments);

     // Log message
    console.log(new Date(), "Exiting:", m);

    return result;
  };
}

Hello! The code example given above is from my coding book. It tries to illustrate a practice called “monkey-patching” using the apply function in JavaScript. I'm really confused about the nature of the line where the original function is invoked:

var result = original.apply(this, arguments); // Invoke original.

As far as I understand, the call to the original function could also be written without the help of apply(), since the thisarg is this, which is to say that the execution context remains unchanged: the original object.

The second point of confusion is where the hell the argumentsargument for apply() comes from? Yes, I know that it is an object generated at every function invocation that is used to access the function arguments - but this line is inside an anonymous function without any arguments. I don't have a clue and am grateful for any hint.

Thank you in advance!


Solution

  • Your first question: Why is apply necessary?

    If you invoke original directly in the anonymous function, this inside original is sure to refer to global (undefined in strict mode). The anonymous function, on the other hand, is declared as a method of o, so if you invoke as o.m(), this inside the anonymous function should refer to o. Passing o to original is desired because it preserved the semantic.

    In addition to binding this, apply can also convert an array of arguments to individual parameters.

    function toBeCalled(x,y){
        console.log('x is: '+x+" y is:"+y)
    }
    
    function x (){
        toBeCalled(arguments)
        toBeCalled.apply(this,arguments)
    }
    
    x('aa','bb','vv')
    
    //x is: [object Arguments] y is:undefined
    //x is: aa y is:bb
    

    See the difference?

    Second question: Where is arguments from?

    In JavaScript, arguments is a built-in variable within the scope of a function. The value of arguments can only be determined when the function is invoked, it is not fixed at all.

    function x (){
        console.log(arguments)
    }
    
    x('aa','bb','vv')
    x("ff","dd")
    x(1123)
    

    arguments is assigned a value when x is invoked, it is dynamic.