var x = 3;
var one = {
x:2,
two: {
x:1,
three:function(){
return this.x;
}
}
}
var go = one.two.three;
console.log(one.two.three() "" go());
Anyone can explain to me why output coming 13 why not 1-undefined?
CodePudding user response:
this
keyword has a different binding that can change during runtime, depending on how the function was invoked.
When a function is on an object, and is accessed through that object, it's this
context will be that object (unless explicitly bound otherwise, but I'll add notes on that later). This means this.x
is referencing the same variable as one.two.x
When you reference that same function into a global variable, the this
context becomes the global space (e.g. the window
object on browsers, or globalThis
in NodeJS). When this happens, this.x
is now referencing global variable x
.
There are other situations where this
context rules are different, such as function closures or class functions.
Functions also have .bind
method that returns a new function with an explicitly bound this
variable.
e.g:
var x = 3;
var one = {
x:2,
two: {
x:1,
three:function(){
return this.x;
}
}
}
one.two.three = one.two.three.bind(one);
var go = one.two.three;
console.log(one.two.three() "" go()); // prints 22
There are also arrow functions, which implicitly have the this
context bound to it's lexical scope... e.g:
var x = 3;
var one = {
x:2,
two: {
x:1,
three: () => {
return this.x;
}
}
}
var go = one.two.three;
console.log(one.two.three() "" go()); // prints 33
This above example prints 33, because the lexical scope is the global scope, thus this.x
is referencing global variable x
.
Hope this answers your question without creating more questions.
Further Reading:
CodePudding user response:
Interesting. I think it has something to do with scopes.
console.log(one.two.three() "" go());
//equals console.log(1 "" 3);
will output 13
(String) because:
one.two.three()
returns1
go()
returns3
- those numbers are concatenated into String with
""
(empty string) in between (instead of-
as you may have asked)
Why go()
returns 3
var x = 3;
// var go = one.two.three;
// equals
var go = function() {
return this.x
}
The declaration var go = one.two.three;
assigns one.two
's three
method as a function into the variable go
in the global scope. The same scope with go
, one
, and x
(with the value 3
), that was declared before declaring one
and go
(var x= 3;
).
Based on your whole codes, this.x
's this
is in the global scope. and this.x
is 3
. So running go()
returns 3
.
one.two.three
is a global function
→ notice there's no ()
, so assigning a function to global scope's variable go
will make the function's scope global.
→ go
function is run under global's scope
Why one.two.three()
returns 1
Well, one.two.three
is a method inside the object two
, which is inside the object one
. While the definition looks the same,
function() {
return this.x;
}
when you run three
method of two
object, return this.x
's this
refers to the method's parent object (which is two
, three
's parent object is two
).
So,
this.x
refers to
two.x
which is 1
.
Hence, in this case return this.x;
outputs 1
.
one.two.three()
is 1
→ notice the ()
which means run the function
→ three
method is run under two
's scope
Addition
This will output 1-undefined
because:
y
is not defined in the global/one
/go
scope- I use
-
as a delimiter inconsole.log
var one = {
y:2,
two: {
y: 1,
three:function(){
return this.y;
}
}
}
var go = one.two.three;
console.log(one.two.three() "-" go());
CodePudding user response:
To assign an object method to a variable, it needs to be bandaged using the bind() function, and if the global variable window is passed to the context, the answer will be 13
*var go = one.two.three.bind(window);*
if the object is one the answer will be 12
*var go = one.two.three.bind(one);*
if the object is two the answer will be 11
*var go = one.two.three.bind(two);*