How do you get the "this" of a function? - javascript

How do you get the this value of a function from outside the function, without having to call it? For example, the following doesn't work, but illustrates the idea:
// window is this, currently
function foo() {}
console.log(foo.this) // would log the window object.
The MDN documentation for Function.bind() reports that bind() "creates a new function that, when called, has its this keyword set to the provided value". This implies that each function has a "this" associated with it from the ery start.
The question is whether or not that "this" is accessible from outside the function call, because presumably it's "this" reference already exists based on thos MDN docs.
Try this in your console:
var foo = function() {}
var bar = foo.bind(this)
console.log(foo === bar)
The result is false, meaning you now have two functions, not one, and each one has it's own this.
Some have mentioned that the "callsite" determines the this of a function, which doesn't seem to be true. If you run
var obj = {}
function foo() {
console.log(this)
}
function Obj(func) {
console.log(this)
func()
}
new Obj(foo)
Then the callsite for foo is inside a new Obj but it still logs the Window object.
If you run
var obj = {}
function foo() {
console.log(this)
}
foo()
foo.call(obj)
foo.bind(obj)
foo()
Then you'll notice that the this of the original foo function has not changed. Based on this fact, and the MDN docs for bind, call, and apply, we can confidently assume that the this for a Function can never be changed.

this can be changed depending on how you call the function, so, there is no real way to get it outside of the function.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/call

No there is no way to get the value of this because this is not actually related to the function object, but to the execution context that is created when the function is called.
An execution context has the following properties:
LexicalEnvironment
Identifies the Lexical Environment used to resolve identifier references made by code within this execution context.
VariableEnvironment
Identifies the Lexical Environment whose environment record holds bindings created by VariableStatements and FunctionDeclarations within this execution context.
ThisBinding
The value associated with the this keyword within ECMAScript code associated with this execution context.
Now, when a function is called, the following steps take place:
10.4.3 Entering Function Code
The following steps are performed when control enters the execution context for function code contained in function object F, a caller provided thisArg, and a caller provided argumentsList:
If the function code is strict code, set the ThisBinding to thisArg.
Else if thisArg is null or undefined, set the ThisBinding to the global object.
Else if Type(thisArg) is not Object, set the ThisBinding to ToObject(thisArg).
Else set the ThisBinding to thisArg.
Let localEnv be the result of calling NewDeclarativeEnvironment passing the value of the [[Scope]] internal property of F as the argument.
Set the LexicalEnvironment to localEnv.
Set the VariableEnvironment to localEnv.
Let code be the value of F’s [[Code]] internal property.
Perform Declaration Binding Instantiation using the function code code and argumentList as described in 10.5.
Notice especially
[...] a caller provided thisArg [...]
This should make clear that the value of this is provided by the caller of the function.
Examples:
When a function is called as foo(), then there is no thisArg, so it is undefined. In that case, step 2 takes place and this is bound to the global object.
However, if a function is called as foo.call(bar), then thisArg is bar and either step 3 or 4 take place, depending on whether bar is an object or not.
I hope this explains why it is not possible to get the this value of a function.

you need a little help from the function.
function foo(){
return this;
};
console.log(foo());

Related

Lost context in object

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?
That's because, its obeying following 2 JS rules
Rule 1. In Javascript, new function = new scope - that’s the rule.
Rule 2. When a function is called as a method of an object, this is set to the object the method is called on.
Explanation of the code:
For rule 2, 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]
For rule 1, the function 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
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)();
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
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
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
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();
};
}

JavaScript time of hoisting

In JavaScript does hoisting occur before or after the creation of the ExecutionContext associated with the function?
I presume before, if so when?
function foo() {
bar();
var x; // When is this hoisted?
function x() {} // ...and when is this hoisted?
};
foo();
Edit: put another way, I believe a graph of objects is instantiated according to the nesting of scopes in the program code, before a single line of code is run. Is the hoisting information stored in this object graph before runtime?
The hoisting happens as part of establishing the execution context:
[[Call]]
When the [[Call]] internal method for a Function object F is called with a this value and a list of arguments, the following steps are taken:
Let funcCtx be the result of establishing a new execution context for function code using the value of F's [[FormalParameters]] internal property, the passed arguments List args, and the this value as described in 10.4.3.
Let result be the result of evaluating the FunctionBody that is the value of F's [[Code]] internal property. If F does not have a [[Code]] internal property or if its value is an empty FunctionBody, then result is (normal, undefined, empty).
[...]
So, when a function is executed, first its execution context is created and then the function body is evaluated. How that happens is described in section 10.4.3:
Entering Function Code
The following steps are performed when control enters the execution context for function code contained in function object F, a caller provided thisArg, and a caller provided argumentsList:
If the function code is strict code, set the ThisBinding to thisArg.
Else if thisArg is null or undefined, set the ThisBinding to the global object.
Else if Type(thisArg) is not Object, set the ThisBinding to ToObject(thisArg).
Else set the ThisBinding to thisArg.
Let localEnv be the result of calling NewDeclarativeEnvironment passing the value of the [[Scope]] internal property of F as the argument.
Set the LexicalEnvironment to localEnv.
Set the VariableEnvironment to localEnv.
Let code be the value of F’s [[Code]] internal property.
Perform Declaration Binding Instantiation using the function code code and argumentsList as described in 10.5.
The hoisting happens in step 9 and is explained in detail in section 10.5. Specifically:
5. For each FunctionDeclaration f in code, in source text order do ...
[...]
8. For each VariableDeclaration and VariableDeclarationNoIn d in code, in source text order do ...
So function declarations are hoisted before variable declarations.

When we store a method in a variable and then call it, Why does the context object change to the global window object?

Below example is taken from jqfundamentals,
var person = {
firstName : 'Boaz',
lastName : 'Sender',
greet : function() {
log( 'Hi, ' + this.firstName );
}
};
var sayIt = person.greet; // store the method in a variable
sayIt(); // logs 'Hi, undefined' -- uh-oh
As explanation,
When we store the .greet() method in a variable sayIt and then call sayIt(), the context object changes to the global window object, not the person object. Since the window object doesn't have a property firstName, we get undefined when we try to access it.
My problem is
When we store the .greet() method in a variable sayIt and then call sayIt() Why does the context object change to the global window object?
It's the spec, See the ecma-262/5.1/#sec-10.4.3
The following steps are performed when control enters the execution
context for function code contained in function object F, a caller
provided thisArg, and a caller provided argumentsList:
If the function code is strict code, set the ThisBinding to thisArg.
Else if thisArg is null or undefined, set the ThisBinding to the global object.
.......
So when in strict mode, this will refer to undefined, otherwise it will refer to the global object.
The context object change to global window because you do not have any context and by default, the "this" refers to window object when there is no context assigned.
You can see an explanation in this link:
http://www.laurencegellert.com/2012/03/javascript-the-good-parts-review/
The behavior the ‘new’ keyword is convoluted and non-obvious. When an object/function is created, adding the new keyword changes the meaning of ‘this’. When ‘new’ is added, ‘this’ refers to the object, which makes sense. However in the next code block, where ‘new’ is omitted, ‘this’ refers to the global Window object! The code example shows how the global object can be polluted. Watch out for ‘this’.

Difference in function scope and context

Does function in javascript have global and local scope?see the code below
function doSomething()
{
function foo()
{
alert(this);
}
foo();
}
foo();
Here function foo() does not get executed. But the "this" keyword within the function points to global window object,if function doSomething() is executed.That means the function foo() is executing on the global scope .since it is executing in global scope why cant we execute the nested function directly without first executing the doSomething().
You're confusing scope and context. The first is fixed for the given function (unless it's returned by some function, effectively being injected into the outer scope), the second (which, among other things, defines what this refers to inside this function) is given to the function when it's invoked - and in fact can be changed with call and apply.
Consider this:
var someObj = function() {
var internalObj = {
nam: 'internal',
doSomething: function() {
console.log('Called from ' + this.name);
}
}
internalObj.doSomething('Internal'); // 1
var someFunc = internalObj.doSomething;
someFunc(); // 2
return {
nam: 'external',
doSomething: internalObj.doSomething
}
}
var x = new someObj();
x.doSomething(); // 3
setTimeout(x.doSomething, 1000); // 4
setTimeout(x.doSomething.bind({nam:'a new one'}), 2000); // 5
JSFiddle.
In this example we define method 'doSomething' as property of internalObj variable, which is local to this constructor function - if you try to access it outside the someObj, you'll get ReferenceError.
When method is called in the constructor function itself (1), you'll get 'Called from internal' logged - as the method's context object (this) refers to internalObj now.
When we assign this method (its reference) to another local variable and call it from there (2), 'undefined' gets logged instead. Scope obviously didn't change here, but context variable did: it refers to the global object now.
Then we return this method as a result of constructor - and things start getting far more interesting: our function is now available in the outer scope! Note, though, the difference between results of its invokations in (3) and (4): the former gives us external (as the context object here is the one that was created by the constructor), the latter, again, return us undefined even though the syntax is the same. ) It happens because functions sent into timeout and event handlers "lose" their context, in short... unless we fix it with Function.prototype.bind method, like in (5).
JavaScript has function level scope.
Any function declaration will be scoped to its nearest containing function automatically.
Function expressions just return a value (that is a function) so you can scope them in any way you choose.
That means the function foo() is executing on the global scope
You are confusing scope and context.
Scope is determined by where a variable is declared (with var or a special rule like "function declarations are scoped"). It effects where a variable is visible.
Context is determined by how a function is called. It effects what the value of this is.
The two are not connected.

accessing global property using "this" keyword inside a function

I do know that in javascript, when you use "this" keyword inside a function, then "this" would refer to the 'owner' of that function according to Quirksmode website. Therefore when we have a function and we use "this" inside it, then "this" refers to the global (window) object.
I am a little confused on how "this" works, for example in the code below, "this" then should be able to resolve x since x is pretty much a property of global object (in this case window). But this.x in this case alerts "undefined" instead of the x value.
var x = "Global";
function foo(){
alert(this.x); //undefined
};
foo();
I then tried some other things too:
function bar(){
function foo(){
alert(this); //[Object DOMWindow]
};
foo();
};
bar();
If my understanding is correct, then 'this' should refer to bar() in that second case since it is the owner of foo(), but why is that it instead still refers to the global object?
Can someone explain what is the correct theory regarding "this" keyword?
You've got the wrong end of the stick. The value of this depends on how the function is called, not how it is defined.
If you call window.foo() then (inside foo) this will be window
If you call bar.foo() then this will be bar (although you need to copy foo so it is a property of bar first)
If you call baz.bar.foo() then this will be bar (you only ever get the parent object via this)
If you call foo.call(bar) then this will also be bar as call lets you override this
If you call new foo() then this will be the new object being created
The default object is window, so if you just call foo() then that is the same as window.foo().
It doesn't matter what scope the function is defined in.
Summarizing your question, you ask why in your first snippet, this.x is undefined:
var x = "Global";
function foo(){
alert(this.x); //undefined
}
foo();
It doesn't make sense at all, the this value should refer to the global object -if your code were on strict mode, you would get a TypeError, since this by itself would be undefined-.
The only way I think where this.x could be undefined, is in the case that the variable declaration of x was made within a function.
Check the two following examples: 1 and 2, it's exactly the same code, the difference is that the second one, the code is wrapped in an onload event handler, so the x variable doesn't exist in the global scope (window.x is undefined)...
Yes, this is always the owner of the function being executed and the best answer about this subject is more than you ever wanted to know about this
var x = "Global";
function foo(){
alert(this.x); // alerts "Global" for me
};
As for the bar(), it is a standalone function and this will be bound to the "global" object as described in the answer linked above, which is your case is the DOMWindow
If you really wish to learn how this works, then read the ECMAscript 262 specs from the section 10.3 Execution Context and onwards.
Here is what it says in section 10.4.3:
10.4.3 Entering Function Code
The following steps are performed when control enters the execution
context for function code contained in function object F, a caller
provided thisArg, and a caller provided argumentsList:
If the function code is strict code, set the ThisBinding to
thisArg.
Else if thisArg is null or undefined, set the ThisBinding to the
global object.
Else if Type(thisArg) is not Object, set the ThisBinding to
ToObject(thisArg) .
Else set the ThisBinding to thisArg.
Let localEnv be the result of calling NewDeclarativeEnvironment
passing the value of the [[Scope]] internal property of F as the
argument.
Set the LexicalEnvironment to localEnv.
Set the VariableEnvironment to localEnv.
Let code be the value of F‘s [[Code]] internal property.
Perform Declaration Binding Instantiation using the function code
code and argumentsList as described in 10.5.

Categories

Resources