Reputation: 536
I have this code:
/// global context
function Outer(){
/// Outer context
this.print = function(){
console.log("1: "+this)
inside(); /// "this" is bound to the global object. Why not bound to the Outer object?
function inside(){
console.log("2: "+this)
}
};
}
function print(){
console.log("3: "+this);
}
var obj = new Outer;
obj.print(); /// "this" is bound to the Outer object.
print(); /// "this" is bound to the global object.
Why inside the method call, this
has a global object? Can anyone explain this?
Upvotes: 2
Views: 510
Reputation: 2238
You can understand it if you read about arrow functions new in ES6.
Until arrow functions, every new function defined its own this value (a new object in the case of a constructor, undefined in strict mode function calls, the base object if the function is called as an "object method", etc.).
Which means that every function defines it's own this
and in case of a simple function it will always be a global object and not the context of a function it is defined in. Just for comparison a function which doesn't define it's own this
(an arrow function):
/// global context
function Outer(){
/// Outer context
this.print = function(){
console.log("1: "+this)
let inside = () => {
/// "this" is Outer object here
console.log("2: "+this)
}
inside();
};
}
Upvotes: 0
Reputation: 2002
the value of this
is depends on how you are making a call to the intended function and generally leading parent object plays important role in it.
what does it mean by leading parent object?:
sampleObj.getDetails(); // here 'sampleObj' is the leading parent object for 'getDetails()' function
lets try to clear the things using some examples of making call to the function using below sample code snippet.
function globalFunction(){
console.log('global this: ', this);
}
var simpleObj = {
name : 'john'
};
var complexObj = {
outer: function(){
console.log('outer this: ', this);
}
}
globalFunction(); // will log global object as no leading parent object is available
complexObj.outer(); // will log 'complexObj' object as leading parent object is 'complexObj'
complexObj.outer = complexObj.outer.bind(simpleObj);
complexObj.outer(); // will log 'simpleObj' object as we have set preference as 'simpleObj' for this **
complexObj.outer.call(); // will log global object as we arent setting any preference for 'this' ***
complexObj.outer.call(simpleObj); // will log simpleObj object as we have set preference as simpleObj for 'this' ***
complexObj.outer.apply(); // will log global object as we arent setting any preference for 'this' ****
complexObj.outer.apply(simpleObj); // will log simpleObj object as we have set preference as simpleObj for 'this' ****
hopefully it will help you!
** what is bind: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind
*** what is call: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/call
**** what is apply: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/apply
Upvotes: 0
Reputation: 3091
That's because, its obeying following 2 JS rules
this
is set to the object the method is called on.Explanation of the code:
this.print()
is a feature of Outer
object. So this
will refer to the Outer object.So the console.log 1 will print 1: [object Object]
inside()
in Outer is not a feature of Outer object. So new scope will created and this
assigned to window. And that's also same for the last function 'print()'So console.log 2 will print 2: [object Window]
And console.log 3 will print 3: [object Window]
as well
Hope Helps,
Run the code: https://es6console.com/j9bxeati/
Reference: https://toddmotto.com/everything-you-wanted-to-know-about-javascript-scope/#function-scope
Upvotes: 3
Reputation: 627
If it is not obvious for you, that probably means you confuse scope and context of the function. Scope is what vars function has access to during invocation. Context (this) is determined by how function is invoked.
Now look on how you invoke your function 'inside' and answer the question. Does it vividly owned by any object? That is why you have global
Upvotes: 1
Reputation: 853
The value of this is determined by how a function is called.
Your "inside" function was called inside "print" function, which has an object reference, but that object did not have "inside" function as a property or that object did not invoke "inside" function.
"this" refers to the object which called it, not the scope in which it is called. Hence, the global object
Upvotes: 0
Reputation: 222855
As the reference states,
In most cases, the value of this is determined by how a function is called. It can't be set by assignment during execution, and it may be different each time the function is called. ES5 introduced the bind method to set the value of a function's this regardless of how it's called, and ES2015 introduced arrow functions which do provide their own this binding (it remains the this value of the enclosing lexical context).
<...>
Inside a function, the value of this depends on how the function is called.
<...>
Since the following code is not in strict mode, and because the value of this is not set by the call, this will default to the global object
<...>
So, in strict mode, if this was not defined by the execution context, it remains undefined.
The posted code is not executed in strict mode, so this
equals to global variable (window
) inside the function when it's called like print()
.
If this is not the desirable behaviour, and print
is expected to be called separately from the object it originally was defined on (e.g. when being passed as a callback), the function can be bound to its lexical this
with arrow in ES6:
function Outer(){
this.print = () => { ... };
}
In ES5 bind
or self = this
recipe can be used:
function Outer(){
this.print = (function(){ ... }).bind(this);
}
function Outer(){
var self = this;
this.print = function(){
self;
...
};
}
If the function isn't expected to be called with another context, it can be called with another context in-place:
print.call(this);
Or:
print.bind(this)();
Upvotes: 1