Verifying my understanding of the scope chain - javascript

(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

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

Enumerating the bound arguments using bind

In JavaScript, can I enumerate the bound arguments for a function?
function foo(a, b) {}
foo = foo.bind(null, '1');
How can I tell that a has been bound to '1'?
Not sure if I understood your question correctly. However, here is a hacky way to get all currently bound arguments of a function.
It works by overwriting the native bind method and storing all bound arguments in a property of the newly bound function.
Function.prototype.bind = (function() {
var bind = Function.prototype.bind;
var slice = Array.prototype.slice;
return function() {
// bind the function using the native bind
var bound = bind.apply(this, arguments);
// store the bound arguments in a property of the bound function
bound.bArgs = (this.bArgs || []).concat(slice.call(arguments, 1));
return bound;
};
})();
function foo(a, b) {}
foo = foo.bind(null, '1');
console.log(foo.bArgs); // ["1"]
foo = foo.bind(null, '2');
console.log(foo.bArgs); // ["1", "2"]
http://jsfiddle.net/49d1xfns/
You cannot. The function is simply being called passed a certain this value and optionally certain argument values: it's not a problem of the called function to distinguish who has been passing those values...
To simplify a bit the issue consider:
function add(x, y) {
return x + y;
}
function bind_first(f, x) {
return function(y) { return f(x, y); };
}
var add3 = bind_first(add, 3);
console.log(add3(2)); // ==> output is 5
the add function is called with two arguments as usual... both of them are coming from the body of an anonymous closure created by bind_first and it's it's nothing that should interest add how this anonymous closure computed the value of those parameters... got them from the outside? were captured variables? computed them itself? are constants?... WHO CARES!
In other words if you want to be able to differentiate between a bound argument and a regular argument there's for sure something wrong in your design (it's none of your business :-) ).
To know how many explicit arguments were bound to a particular function, you'd need to know:
The number of explicit arguments in the original function
The number of explicit arguments in the bound function
This can be achieved if you have access to both the original function and the newly bound function. This also assumes that the binding was done with an ES5 compliant Function.prototype.bind call.
The way you'd figure out which arguments were bound is by subtracting the newly bound function's length from the original function's length:
var foo = function (a, b, c) {...};
var bar = foo.bind(fizz, buzz);
var argumentsBound = foo.length - bar.length; // 1
var argumentNames = ['a', 'b', 'c'].slice(0, argumentsBound); // 'a'
Details for why this works can be found in the ES5 spec (15.3.4.5, #15)
If the [[Class]] internal property of Target is "Function", then
Let L be the length property of Target minus the length of A.
Set the length own property of F to either 0 or L, whichever is larger.
All of that said, this doesn't give much access at all to which properties were bound, and is pretty well useless within the original function (foo in my example above) because the original function probably shouldn't reference bound derivative functions.
This also doesn't help at all if no arguments are defined on the function. If you're making use of arguments to pass additional parameters, the length property is no longer relevant.

Understanding JavaScript this with private function and self executing function

I was reading Angus Croll understanding JS this blog and found this
var a = {
b: function() {
var c = function() {
return this;
};
return c();
}
};
a.b();//window
To me it looks like, at the time of invoking c, c was inside b. that should be the invoking context (correct me, if i am wrong). when it executes, Why context(this) of c() is window?
there is another example i found in that blog
var a = {
b: function() {
return (function() {return this;})();
}
};
a.b(); //window
why context of b is window? Does anonymous function always run in the global context?
Here's a good way to understand this (pun intended):
The value of this inside a function is determined by the way the function is called. With one exception, it doesn't have to do with where the function is defined, what other functions it may be nested inside, what object it was defined as part of, what kind of function it is, or any of that.
When you call a function using a method call like foo.bar() or foo[bar](), this inside the function is the foo object.
When you call a function with an ordinary function call like foo(), this in the function is the window object, or if the function uses strict mode it is undefined.
That's the one exception - if the function itself or its surrounding code has "use strict"; it changes this for a plain function call. For good code that shouldn't make a difference - you shouldn't be writing code that depends on this being the window object anyway.
Otherwise, what you care about is what object this refers to in a method call. And that's always determined by how the function is called, not how it's defined.
Let's go through your first example.
When you call a.b(), you're calling b as a method of the a object. So inside the b function, this is the same as a.
As it happens, it doesn't do us any good to know that, because the b function never does anything with this. All it does is call c() as an ordinary function. So inside c, this is the window object, or it would be undefined if you were in strict mode.
The c function simply returns its this value, or window. And that is also the return value from b. So that's why you see window as the result: it all comes from how the code calls the b and c functions.
Now about the second example: well, that's just terribly obfuscated code, isn't it? Who would ever write this code and expect anyone to understand it at first glance?
So let's turn it into a more readable form. This line is the problem:
return (function() {return this;})();
Let's take out the parenthesized function expression:
(function() {return this;})
and assign it to a temp variable:
var temp = (function() {return this;});
We don't need the extra parentheses any more, and let's indent the code for readability:
var temp = function() {
return this;
};
and we can call that temp variable as a function in the return statement:
return temp();
Now we can put this back into the b function in the code example:
var a = {
b: function() {
var temp = function() {
return this;
};
return temp();
}
};
a.b(); //window
Hey! Doesn't that code look familiar? In fact, it's identical to the first example except for the name of the temp variable. So now you see why it works the same as the first one.
One key to look for is the new keyword, which establishes a new context. Don't see a new? Then the context hasn't changed, which means this hasn't changed. If you called this from within window, then that's your context, and that's your this. (This changes if you use call() or apply() with a scope, but that obviously doesn't apply here.)

Does the Arguments object leak?

Assuming I had this sloppy-mode function, which (for some odd reason) returns its arguments object to the caller:
function example(a, b/* ...*/) {
var c = // some processing
return arguments;
}
Does storing the result of an invocation (var d=example();) prevent the variable environment of example (containing a, b, c etc) from being garbage-collected? The internal setters and getters of the Arguments object might still refer to it, just like a function returned from a closure does. Demo:
function example(a, b) {
var c = Array(1000).fill(0); // some large object
return {
args: arguments,
set: function(x) { a = x; },
get: function() { return a; }
};
}
var d = example('init');
console.log(d.get());
d.args[0] = 'arguments update'; // assigns the `a` variable
console.log(d.get());
d.set('variable update');
console.log(d.args); // reads the `a` variable
I know there is hardly a use case (and passing around Arguments objects is considered bad practice, most likely because of their similarity to arrays), but this is more a theoretical question. How do different EcmaScript implementations handle this? Is it implemented close to the spec?
I would expect c to be garbage-collected like with a normal closure and not to be leaked, but what about b? What would happen if I delete the properties of the arguments object?
Consider this:
var x = function() {
return arguments;
}
console.log( x() === x() );
It's false, because it's not the same arguments object: it's (for each invokation of x) a newly constructed object that has the values of all the params stored within. Yet it has properties of arguments:
var y = x([]);
console.log(y instanceof Object); // true
console.log(y instanceof Array); // false
console.log(y.length); // 1
console.log(y.callee + ''); // function() { return arguments; }
Yet there's more to this. Obviously, objects sent into function as its params will not be collected by GC if arguments are returned:
var z = x({some: 'value'});
console.log(z[0]); // {some:'value'}
This is expected: after all, you can get the similar result by declaring some local object inside the function, assigning the value of the function's first parameter as its object '0' property, then returning this object. In both case the referred object will still be "in use", so no big deal, I suppose.
But what about this?
var globalArgs;
var returnArguments = function() {
var localArgs = arguments;
console.log('Local arguments: ');
console.log(localArgs.callee.arguments);
if (globalArgs) { // not the first run
console.log('Global arguments inside function: ');
console.log(globalArgs.callee.arguments);
}
return arguments;
}
globalArgs = returnArguments('foo');
console.log('Global arguments outside function #1: ');
console.log(globalArgs.callee.arguments);
globalArgs = returnArguments('bar');
console.log('Global arguments outside function #2: ');
console.log(globalArgs.callee.arguments);
Output:
Local arguments: ["foo"]
Global arguments outside function #1: null
Local arguments: ["bar"]
Global arguments inside function: ["bar"]
Global arguments outside function #2: null
As you see, if you return arguments object and assign it to some variable, inside the function its callee.argument property points to the same set of data as arguments itself; that's, again, expected. But outside the function variable.callee.arguments is equal to null (not undefined).
Without having done any research into a particular JavaScript engine this is hard to answer conclusively. I would however argue that the relation between the arguments Object and the context created by example is the same as of any other local variable and its host context.
That is to say, storing the value does not require its context to be stored as well.
One caveat is the arguments.callee property which is a reference to the context (i.e. Function) which a given arguments Object is bound to. This property however does not exist in strict mode and also has been deprecated.
Other than that I think it's safe to assume that returning and storing the arguments Object won't lead to a memory leak.

Categories

Resources