Confused about execution context in JS - javascript

// 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!

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.

Related

redefine function definition in javascript without reassigning it

Functions are callable objects in javascript so is it possible to redefine a function definition
?
so basically what I am trying to do is:
let a = function(){console.log('first');}
let b = a;
/**
* alter definition of function 'a' something like:
a.redefine(function(){console.log('second');});
*/
b();//should log 'second'
I looked up for javascript function documentation here as well as here but couldn't find any reference on how/where functions definition are actually stored, even tried to inspect a.prototype as well as altering a.prototype.constructor but got nothing.
A workaround on this can be something like:
let functionHolder={
a:function(){console.log('first');}
}
let a = function(){functionHolder.a();}
let b = a;
functionHolder.a=function(){console.log('second');}
b();//would log 'second'
however my ultimate goal is to understand how functions actually work/stored in js and not a workaround just to achieve this.
It's not possible. Once a function has been defined, its "function code" is immutable. The only way for a variable name which references a function to reference different "function code" would be to reassign the variable name to a new function.
Your
functionHolder.a=function(){console.log('second');}
is essentially the same thing - you're reassigning the function that functionHolder.a refers to.
In the specification, when you call a function, you invoke its internal method [[Call]], which eventually leads you to
OrdinaryCallEvaluateBody, which does:
Return the result of EvaluateBody of the parsed code that is F.[[ECMAScriptCode]] passing F and argumentsList as the arguments.
And the ECMAScriptCode internal property is not reassignable - it's only set in FunctionInitialize, when a new function is created (like when you do
<someIdentifier> = function(){console.log('second');}
)
It is possible by turning the b variable into a getter on the window object.
It's not pretty, but it works:
let a = () => "foo";
console.log("a", a());
Object.defineProperty(window, 'b', {
get() { return a; }
});
console.log("b", b());
a = () => "bar";
console.log("b", b());
a is a reference to a function. Call it a "pointer".
b is a copy of that pointer.
When you re-assign a, you're replacing the pointer. If another variable still points to the value behind the old pointer, that value still exists. That's why in your example, b didn't change: b was a pointer to the old function.
That getter is basically a function that's executed without explicitly having to call it, so it always gets the latest result of whatever the getter function does.

confused again by javascript this

some updates:
thank all for all your help. i guess this might be the key confusion point: "this" in the param area is not considered "inside" the function, and thus will not follow the rule (this points to the obj the method is called on) mdn specified. example below:
someObj {
someF(//but if "this" shows up here, it doesn't point to someObj) {
//when called, "this" here will point to someObj
}
}
original question:
After reading many docs, I thought I had a good understanding of this, but I was wrong.
The example below is from MDN:
function Counter() {
this.sum = 0;
this.count = 0;
}
Counter.prototype.add = function(array) {
// Here "this" points to obj
array.forEach(function(entry) {
this.sum += entry;
++this.count;
}, this);
// ^---- Note, why it points to obj, not array [2,5,9]???
// Here "this" points to obj
};
const obj = new Counter();
obj.add([2, 5, 9]);
obj.count;
// 3
obj.sum;
// 16
I understand:
The needs to pass in this to a forEach, otherwise in the callback function, this would point to global/window (non-strict mode).
Within most areas of function(array), this points to obj (created from new Counter()), as shown by the comments.
How the callback function uses "this" passed from forEach as the 2nd param. I don't have any question about it
But based on this article on MDN
specifically:
"As an object method, when a function is called as a method of an
object, its this is set to the object the method is called on."
Shouldn't the this (highlighted by ^---Note) passed into the callback point to the array object, i.e., [2,5,9] in this case. Why would it point to obj instead of the array?
Thanks a lot for the help, it's just so confusing.
the needs to pass in "this" in forEach, otherwise "this" in internal function would point to global/window (non-strict mode).
The value of this depends on how the function is called. You can't see the code which calls the callback function you pass to forEach (it is internal to the browser). As it happens, it does call it that way, so it is window (if you don't pass a second argument to forEach).
As an object method, when a function is called as a method of an object, its this is set to the object the method is called on
This is irrelevant. You aren't calling the callback function as a method of an object. You're passing it to forEach … and then forEach is calling it.
You are calling forEach as a method of the array, so inside the forEach function — which you can't see because it is internal to the browser — this will be the array.
Why it would point to obj instead of the array?
Because forEach is explicitly designed to call the callback function in such a way that the second argument to forEach is the this value inside the callback function.
You quoted the documentation that said so.
You will probably see it easier in the following passing in a reference to the object's this as the thisArg of forEach()
Counter.prototype.add = function(array) {
//here "this" points to obj
const _self = this
array.forEach(function(entry) {
// _self passed in as second argument is now `this`
console.log(this === _self) // true
this.sum += entry;
++this.count;
}, _self);
// ^---- passing in reference to the `add` object instance `this`
};
I think your confusion is stemming from the words "called on" in the quote from MDN, and I wouldn't say that is your fault. It doesn't really sound wrong that to say, in the case of obj.add([2, 5, 9]), obj.add is being "called on" [2, 5, 9]. However, what they're trying to say is that the add method is being "called on" obj.
Regardless of how you want to word it, the way it works (in general) is if you're calling a function from a property of an object, that object is what this will point to inside that function. In the case of obj.add([2, 5, 9]), the add function is being accessed via the object obj, so obj is set to this inside that call of add.
This problem is exactly why arrow functions were introduced. They are more tightly bound to your enclosing closure.
function Counter() {
this.sum = 0;
this.count = 0;
}
Counter.prototype.add = function(array) {
array.forEach(entry => {
/*
Because we are using an arrow function here, it is using the
enclosing closure (which originates from `obj`).
*/
this.sum += entry;
++this.count;
});
};
const obj = new Counter();
obj.add([2, 5, 9]);
console.log(obj.sum);
console.log(obj.count);
From the linked documentation:
An arrow function does not have its own this. The this value of the enclosing lexical scope is used; arrow functions follow the normal variable lookup rules. So while searching for this which is not present in current scope, an arrow function ends up finding the this from its enclosing scope.

javascript - what does this line mean: var result = original.apply(this, arguments)

just started learning javascript from the book the definitive guide, there is one line which I couldn't figure it out. Here is the complete code:
// 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) {
var original = o[m]; // Remember original method in the closure.
o[m] = function() { // Now define the new method.
console.log(new Date(), "Entering:", m); // Log message.
var result = original.apply(this, arguments); // Invoke original.
console.log(new Date(), "Exiting:", m); // Log message.
return result; // Return result.
};
}
the author did not comment on the line and I have a few questions regarding this code.
What does this, arguments refer to respectively? How is this invocation works exactly?
Explanations on the closures in this particular code would be welcomed too!
Thank you
apply is invoking the function referenced by o[m], using this as the "context" and forwarding the arguments passed to the replacement function onto the original function.
The "context" is referring to the "this"-binding of the function. If you were to say var result = original.apply(null, arguments); then the "context" would be set to null, and any call to "this" in the original function would (more or less) be replaced by "null".
In this case, calls to this in m are probably expected to refer to o, since it is the containing object.
Javascript binds the special this and arguments variables when a function is called: this refers to the function's caller and arguments stores all passed arguments in an array-like object. The line original.apply(this, arguments) invokes the function original with the same this binding and the same arguments, in the same order, as the function in which the line occurs (here, an anonymous function stored at o[m]).

Passing "extra" arguments to a function stored in a variable - Javascript

I'm new to Javascript, I'm self-teaching, so this might be an obvious area, but no matter how I phrase the question I can't really seem to get my head around this one issue. At the moment I'm reading through http://eloquentjavascript.net/chapter6.html (which was on mozilla's MDN). I've come across this a couple of times now, I would just like a simple break down if possible.
function negate(func) {
return function(x) {
return !func(x);
};
}
var isNotNaN = negate(isNaN);
show(isNotNaN(NaN));
I don't understand how at the very last step isNotNaN (a variable) is passing an 'extra argument' (NaN) to the function stored in isNotNaN (negate(isNaN). "show(isNotNaN(NaN));"
I came across this same problem when the concept of enclosure was trying to be explained. But I don't get where this argument "NaN" is going in the above function, as it seems to me like the last statement ends up something like:
show(negate(isNaN, NaN));
I would be happy to provide more details. This concept of passing an extra argument to a variable already holding a function with an argument confuses the hell out of me!
There's no "extra" argument. The negate() function itself returns a function defined as a function expression, which can then be called with any number of original (not extra) arguments passed. A closure is used for the returned function to keep a reference to isNaN as func.
var isNotNaN = negate(isNaN);
At this point, isNotNaN contains a reference to the function
function(x) {
return !func(x);
};
Again, func here refers to the isNaN argument passed to the negate function, which is the immediate parent in the scope chain. The result is similar, but not the same as
var isNotNaN = function (x) {
return !isNaN(x);
};
The reason it is not the same is, if we change the value of isNaN, the behaviour of this function will change. In the example you posted, however, the value of func is equal to the original value of isNaN and cannot be changed by anything outside of its scope thanks to the closure.
Essentially, you can pass in any function and get a new function that returns the negated result of the original function in return. For example:
var isNotArray = negate(Array.isArray);
isNotArray(12);
//-> true
In fact, negate(isNaN) simply return a function to the variable isNotNaN. This function take a parameter (named x in your case), then execute the function isNaN on the parameter before negating it and returning the result.
Perhaps this example can clear some things out for you regarding closures:
function foo(x){
function bar(y){
return x+y;
}
return bar;
}
var fooRef = foo(1); // fooRef references foo() with x set to 1
console.log(fooRef(2), foo(1)(2)); // 3, 3
http://jsfiddle.net/ePwy8/

Verifying my understanding of the scope chain

(Question 1)
In Flanagan's JS Definitive Guide, he defines the Function method bind() in case it's not available (wasn't available n ECMAScript 3).
It looks like this:
function bind(f, o) {
if (f.bind) return f.bind(o); // Use the bind method, if there is one
else return function() { // Otherwise, bind it like this
return f.apply(o, arguments);
};
}
He illustrates the use of it with an example (which I have modified to change the 3rd line from f.bind(o)):
function f(y) { return this.x + y; } // This function needs to be bound
var o = { x : 1 }; // An object we'll bind to
var g = bind(f, o); // Calling g(x) invokes o.f(x)
g(2) // => 3
When I first saw this, I thought "Wouldn't arguments refer to the arguments variable within the bind function we're defining? But we want the arguments property of the function we eventually apply it to, like g in the example above..."
I verified that his example did indeed work and surmised that the line return f.apply(o, arguments) isn't evaluated until var g = bind(f, o) up above. That is, I thought, when you return a function, are you just returning the source code for that function, no? Until its evaluated? So I tested this theory by trying out a slightly different version of bind:
function mybind2(f, o) {
var arguments = 6;
return function() { // Otherwise, bind it like this
return f.apply(o, arguments);
};
}
If it's simply returning tbe unevaluated function source, there's no way that it stores arguments = 6 when later evaluated, right? And after checking, I still got g(2) => 3. But then I realized -- if it's just returning unevaluated code, how is the o in return f.apply(o, arguments) getting passed?
So I decided that what must be happening is this:
The o and the arguments variables (even when arguments equals 6) are getting passed on to the function. It's just that when the function g is eventually called, the arguments variable is redefined by the interpreter to be the arguments of g (in g(2)) and hence the original value of arguments that I tried to pass on was replaced. But this implies that it was sort of storing the function as text up until then, because otherwise o and arguments would have simply been data in the program, rather than variables that could be overwritten. Is this explanation correct?
(Question 2) Earlier on the same page, he defines the following function which makes use the apply method to trace a function for debugging:
function trace(o, m) {
var original = o[m]; // Remember original method in the closure.
o[m] = function() { // Now define the new method.
console.log(new Date(), "Entering:", m); // Log message.
var result = original.apply(this, arguments); // Invoke original.
console.log(new Date(), "Exiting:", m); // Log message.
return result; // Return result.
};
}
Wouldn't the this here refer to the function that we're defining, rather than the object o? Or are those two things one and the same?
Question 1
For your first question, let's simplify the example so it's clear what being done:
function bind(func, thisArg) {
return function () {
return func.apply(thisArg, arguments);
};
}
What happens here is that a closure is created that allows the access of the original function and the value of this that is passed. The anonymous function returned will keep the original function in its scope, which ends up being like the following:
var func = function () {};
var thisArg = {};
func.apply(thisArg, [/*arguments*/]);
About your issue with arguments, that variable is implicitly defined in the scope of all functions created, so therefore the inner arguments will shadow the outer arguments, making it work as expected.
Question 2
Your problem is to your misunderstanding of the late binding of this -- this is one of the more confusing things about JavaScript to people used to more object-oriented languages that also have their own this keyword. The value of this is only set when it is called, and where it is called defines the value of this when it is called. It is simply the value of the parent object from where it is at the time the function is called, with the exception of cases where the this value is overridden.
For example, see this:
function a() {return this;};
a(); // global object;
var b = {};
b.a = a;
b.a(); // object b
If this was set when the function was defined, calling b.a would result in the global object, not the b object. Let's also simplify what happens with the second function given:
function trace(obj, property) {
var method = obj[property]; // Remember original method in the closure.
obj[property] = function () { // Now define the new method.
console.log(1); // Log message.
// Invoke original method and return its result
return original.apply(this, arguments);
};
}
What happens in this case is that the original method is stored in a closure. Assigning to the object that the method was originally in does not overwrite the method object. Just like a normal method assignment, the principles of the this value still work the same -- it will return the parent object, not the function that you've defined. If you do a simple assignment:
var obj = {};
obj.foo = function () { return this; };
obj.foo(); // obj
It does what was expected, returns the parent object at the time of calling. Placing your code in a nested function makes no difference in this regard.
Some good resources
If you'd like to learn more about writing code in JavaScript, I'd highly recommend taking a look at Fully Understanding the this Keyword by Cody Lindley -- it goes into much more detail about how the this keyword behaves in different contexts and the things you can do with it.
But this implies that it was sort of storing the function as text up until then, because otherwise o and arguments would have simply been data in the program, rather than variables that could be overwritten. Is this explanation correct?
No. this and arguments are just special variables which are implicitly set when a function is executed. They don't adhere to normal "closure rules". The function definition itself is still evaluated immediately and bind returns a function object.
You can easily verify this with:
var g = bind(f, o);
console.log(typeof g);
Here is a simpler example which doesn't involve higher order functions:
var arguments = 42;
function foo() {
console.log(arguments);
}
foo(1, 2);
I think you see that the definition of foo is evaluated like you'd expect. Yet, console.log(arguments) logs [1, 2] and not 42.
Wouldn't the this here refer to the function that we're defining, rather than the object o? Or are those two things one and the same?
this never refers to the function itself (unless you explicitly set it so). The value of this is completely determined by how the function is called. That's why this is often called "the context". The MDN documentation provides extensive information about this.
Reading material:
MDN - this
MDN - arguments

Categories

Resources