Regarding this code:
var name = "Jaguar";
var car = {
name:"Ferrari",
getName:function(){
return this.name;
}
};
alert((car.getName = car.getName)());
The output is: Jaguar
.
Why does this
object correspond to Window
and not the object contained in the car
variable?
It seems that the fact to reassign the object's function to itself leads to lose the assignment of this
to the object when the function is called...
I'm trying to guess: Does it exist a kind of mechanism (using variable or other) that keep an eye on the non-reassignement of an object's function so that if that situation happens, this mechanism would prevent the assignement of the this
keyword as usual (as being equals to the object)?
The reason is fairly subtle: this
in JavaScript is determined entirely by how a function is called. To have this
set to car
during the call to getName
, you have to call getName
immediately upon retrieving it from the car
object, like this:
car.getName() // or
car["getName"]()
(Or via Function#call
or Function#apply
, which let you specify the value for this
explicitly.)
What you're doing in your example is effectively this:
// Set f to the result of the assignment expression,
// which is a reference to the getName function
var f = (car.getName = car.getName);
// Call it (separately)
f();
...which is different. Functions called in that way get this
set to the global object (window
, in browsers). (Except in strict mode; in strict mode this
would be undefined
.)
More (from my anemic blog):
this
Does it exist a kind of mechanism (using variable or other) that keep an eye on the non-reassignement of an object's function so that if that situation happens, this mechanism would prevent the assignement of the this keyword as usual (as being equals to the object)?
I'm not entirely sure I follow that question, but if you want to have a function that always has a preset this
value, then yes, there are a couple of ways to do that.
One is to use the new ES5 function bind
:
var name = "Jaguar";
var car = {
name: "Ferrari"
};
car.getName = function(){
return this.name;
}.bind(car);
alert((car.getName = car.getName)()); // "Ferrari"
bind
returns a function that always has this
set to the argument you give it.
The other way is to use a closure. And in fact, you can create a bind
-like function in ES3 very easily:
function pseudoBind(func, thisArg) {
return function() {
return func.apply(thisArg, arguments);
};
}
That doesn't do everything bind
does, but it does the this
part. Then you'd have:
var name = "Jaguar";
var car = {
name: "Ferrari"
};
car.getName = pseudoBind(function(){
return this.name;
}, car);
alert((car.getName = car.getName)()); // "Ferrari"
More on closures (again from the blog):
In a future spec, we'll be getting a declarative way of creating functions that have a preset this
value (so-called "arrow functions" because the syntax for them involves uses =>
rather than the function
keyword).
Aaah, this
resolution...Lets take a gander.
var toy = {
log : function () { console.log(this); }
};
toy.log() //logs the toy object
So far, it seems like this
resolution is static: Wherever the method was defined in, that's its this
value.
But! What if we do this:
var sneakyBastard = toy.log;
sneakyBastard(); //logs Window
this
is bound to the object it's called with. In the case of toy.log
, you called log
in the context of the toy
object. But, sneakyBastard
has no set context, so it's as if you've called window.sneakyBastard
.
Now let's take a goose (goose? gander? no...) at your expression:
(car.getName = car.getName)()
...and what does an assignment return? The assigned value, in this case, a function, car.getName
. We can break this expression into two:
var returnedValue = (car.getName = car.getName);
returnedValue();
...and from here it's obvious.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With