I understand the later, we call the alert on the foo
object, which has another object named baz
as its property, which in turn has a method named bar
that returns the value of x
. And because of lexical scope
(I think :) ) the JS piler/interpreter goes up the chain, finds x
in baz
and returns 1.
My guess is when assigned to the variable go
and then called from the global scope, you get 3? Just want to find out what's happening in the background. Any help will be appreciated!!!
var x = 3;
var foo = {
x: 2,
baz: {
x: 1,
bar: function() {
return this.x;
}
}
}
var go = foo.baz.bar;
alert(go());
alert(foo.baz.bar());
I understand the later, we call the alert on the foo
object, which has another object named baz
as its property, which in turn has a method named bar
that returns the value of x
. And because of lexical scope
(I think :) ) the JS piler/interpreter goes up the chain, finds x
in baz
and returns 1.
My guess is when assigned to the variable go
and then called from the global scope, you get 3? Just want to find out what's happening in the background. Any help will be appreciated!!!
var x = 3;
var foo = {
x: 2,
baz: {
x: 1,
bar: function() {
return this.x;
}
}
}
var go = foo.baz.bar;
alert(go());
alert(foo.baz.bar());
Share
Improve this question
edited Feb 12, 2015 at 15:39
Antonio Pavicevac-Ortiz
asked Feb 12, 2015 at 14:16
Antonio Pavicevac-OrtizAntonio Pavicevac-Ortiz
7,75920 gold badges75 silver badges156 bronze badges
2
-
1
All because of execution context... first alert of
3
becausethis
refers to global context and thusthis.x
returns 3..and 1 is pretty much obvious.. – Rakesh_Kumar Commented Feb 12, 2015 at 14:21 -
go()
will return undefined... it is not a function but a variable! – kasper Taeymans Commented Feb 12, 2015 at 14:22
5 Answers
Reset to default 7When you do something like this:
var go = foo.baz.bar;
go();
you will find that go
has lost the reference to foo.baz
before calling bar()
. It is just a pointer to the bar
function and has no association with the object that it is attached to any more. That means that this
will not be foo.baz
when the bar
method executes.
This is explicitly what .bind()
was developed for. You can use it like this:
var go = foo.baz.bar.bind(foo.baz);
go();
And, it will then work for you. You can also do the manual version of the same thing:
var go = function() {return foo.baz.bar();}
go();
but .bind()
is built into the language now to help you solve this type of issue.
In first you declare a function expression to a variable with name go
. If you execute function go
this
refers to the global object and there the variable x
has value 3 so that's why it alert(go())
alerts 3. On the other hand you execute the method foo.baz.bar()
. Here this
refer to the object(foo
) and the x
has the value 1
. So it alerts 1
.
var x = 3;
var foo = {
x: 2,
baz: {
x: 1,
bar: function() {
return this.x;
}
}
}
//here you save a function expression
//to a variablewith name go
var go = foo.baz.bar;
//you execute go but this refer to the global object
//and x has the value of 3 in the global object
console.log(go());//this will output 3
//this refer to the object foo where x has
//the value of 1
console.log(foo.baz.bar());//this will output 3
the go-function runs in the window, the foo.baz.bar-function runs within the object. do this instead to get it to return the inner x:
var go = function(){ return foo.baz.bar(); };
Edit: A good rule of thumb: functions run in the scope they are declared in.
the same thing can be seen in .toString()
Number(123).toString()
gives a different result than
Number(456).toString()
Even though the same function is called.
The function is actually located in the Number.prototype object.
Since you're fetching a function into a variable you're essentially transferring the function to the global scope, yes.
For example, if your object bar also had a function foo() and you'd fetch foo.baz.bar and bar would contain return this.foo(); it would error. foo() does no longer exist since you assigned just that function, and not the object it belonged to originally, to a variable. As in, it's not by reference.
In this case it is only about execution context. The function is always the same, the only thing that changes is the meaning of the 'this' object within the function.
You can specify the context by using .apply(), and also you can force permanently a specific context with .bind()
You can see it in my version of your code:
var x = 3;
var foo = {
x: 2,
baz: {
x: 1,
bar: function() {
return this.x;
}
}
}
var go = foo.baz.bar;
alert(go.apply(this));
alert(go.apply(foo));
alert(go.apply(foo.baz));
var goBinded = foo.baz.bar.bind(foo.baz);
alert(goBinded());
alert(goBinded.apply(foo));