Understanding the this keyword - javascript

So I have been researching the keyword "this" in JS and im not sure if I fully understand it clearly. So in an attempt to understand the "this" keyword, I started off by creating a JS object and seeing if I can return a value based on some math executed with the this keyword. The following code below is my initial attempt:
let myObject = {
objectFunc: function() {
this.thing = 10;
},
addFunc: function(x) {
let result = this.thing + x;
return result;
}
}
console.log(myObject.addFunc(20));
So I expected this console log to return 30, however Im getting a "NaN" in the console. Can someone explain to me why? and also point me to some easier to understand documentation/explanation that isn't the MDN linked above?

You're on the right track. The reason why it's giving you NaN is because "this.thing" hasn't been defined yet. It's only defined when you call myObject.objectFunc() first.
let myObject = {
objectFunc: function() {
this.thing = 10;
},
addFunc: function(x) {
let result = this.thing + x;
return result;
}
}
myObject.objectFunc()
console.log(myObject.addFunc(20));

An easy to understand explanation would be that JavaScript 'this' keyword refers to the object it belongs to. The value of 'this' differs depending on how a function is invoked. There are four rules for 'this', in order of precedence that can be used to determine what 'this' gets bound to.
Rule 1. Default Binding: When invoking a function declaration 'this' keyword bounds to the global object.
Rule 2. Implicit Binding: When dot notation is used to invoke a function.
Rule 3. Explicit Binding: When .call(), .apply(), or .bind() are used on a function.
Rule 4. New Binding: When invoking a function by the new keyword, 'this' bounds to newly created object.

Related

In Factory functions are object names and 'this' keyword often or always interchangeable?

The following code doesn't throw an error but I'm not entirely sure why.
In the doubleIt method I use the name of the object, returnObject instead of this.
After newInstance is instantiated I would expect that the term returnObject would be copied into the new doubleIt method. Because returObject only exists in the factory function if doubleIt was called from newInstance it would confuse the JS engine and throw an error. However it doesn't, it works fine. Why does this still work?
"use strict"
function factoryFunction(x) {
let returnObject = {
oneParameter: x,
doubleIt: () => returnObject.oneParameter * 2
// doubleIt: () => this.oneParameter * 2
// Why don't I have to use the 'this' version?
}
return returnObject;
}
let newInstance = factoryFunction(10);
console.log(newInstance.doubleIt());
The way javascript deals with situations like this is described in painstaking detail in documents like this.
That's not easy to parse for most humans, but the gist is that the left hand side of an assignment is processed first. So in your example returnObject gets a reference to the object. After than the value of the object is evaluated. So it sees that you are using returnObject which it already has a reference to and is able to lookup the oneParameter property at runtime. All this is captured in a closure, which means the returned object has access to the name returnObject.
To show that it's actually evaluating at runtime, you can change oneParameter and then call the function. It works as expected:
"use strict"
function factoryFunction(x) {
let returnObject = {
oneParameter: x,
doubleIt: () => returnObject.oneParameter * 2
// doubleIt: () => this.oneParameter * 2
// Why don't I have to use the 'this' version?
}
return returnObject;
}
let newInstance = factoryFunction(10);
newInstance.oneParameter = 100
console.log(newInstance.doubleIt());
Also, returnObject is not copied into the new doubleIt — doubleIt just has a reference that points to returnObject.
A closure captures its environment variables. Since returnObject was defined as a variable outside the closure, it will be captured by the closure.
What will happen in this case, is that a circular reference will be created where the closure doubleIt() will have a reference to returnObject and returnObject will have a reference to doubleIt().
With regard to "this", in your example, it refers to the window object, since the factory function was not invoked with "new". If it is invoked with "new", then it will refer to the factoryFunction. However, it will never refer to returnObject, since returnObject itself was never invoked with "new". In order to have "this" point to returnObject within doubleIt(), you will need to define a function for returnObject that will be invoked with new. The following snippet will work if you invoke factoryFunction with or without "new":
function factoryFunction(x) {
let returnObject = function(x) {
this.oneParameter = x;
this.doubleIt = () => this.oneParameter * 2;
};
return new returnObject(x);
}
let newInstance = factoryFunction(10);
let anotherNewInstance = new factoryFunction(10);
console.log(newInstance.doubleIt());
console.log(anotherNewInstance.doubleIt());
JavaScript object orientation is different from "classic" object orientation. When you create the new object returnObject is assumed as "this", since it is the object.

Javascript this when invoking a constructor? [duplicate]

I just came across an interesting situation in JavaScript. I have a class with a method that defines several objects using object-literal notation. Inside those objects, the this pointer is being used. From the behavior of the program, I have deduced that the this pointer is referring to the class on which the method was invoked, and not the object being created by the literal.
This seems arbitrary, though it is the way I would expect it to work. Is this defined behavior? Is it cross-browser safe? Is there any reasoning underlying why it is the way it is beyond "the spec says so" (for instance, is it a consequence of some broader design decision/philosophy)? Pared-down code example:
// inside class definition, itself an object literal, we have this function:
onRender: function() {
this.menuItems = this.menuItems.concat([
{
text: 'Group by Module',
rptletdiv: this
},
{
text: 'Group by Status',
rptletdiv: this
}]);
// etc
}
Cannibalized from another post of mine, here's more than you ever wanted to know about this.
Before I start, here's the most important thing to keep in mind about Javascript, and to repeat to yourself when it doesn't make sense. Javascript does not have classes (ES6 class is syntactic sugar). If something looks like a class, it's a clever trick. Javascript has objects and functions. (that's not 100% accurate, functions are just objects, but it can sometimes be helpful to think of them as separate things)
The this variable is attached to functions. Whenever you invoke a function, this is given a certain value, depending on how you invoke the function. This is often called the invocation pattern.
There are four ways to invoke functions in javascript. You can invoke the function as a method, as a function, as a constructor, and with apply.
As a Method
A method is a function that's attached to an object
var foo = {};
foo.someMethod = function(){
alert(this);
}
When invoked as a method, this will be bound to the object the function/method is a part of. In this example, this will be bound to foo.
As A Function
If you have a stand alone function, the this variable will be bound to the "global" object, almost always the window object in the context of a browser.
var foo = function(){
alert(this);
}
foo();
This may be what's tripping you up, but don't feel bad. Many people consider this a bad design decision. Since a callback is invoked as a function and not as a method, that's why you're seeing what appears to be inconsistent behavior.
Many people get around the problem by doing something like, um, this
var foo = {};
foo.someMethod = function (){
var that=this;
function bar(){
alert(that);
}
}
You define a variable that which points to this. Closure (a topic all its own) keeps that around, so if you call bar as a callback, it still has a reference.
NOTE: In use strict mode if used as function, this is not bound to global. (It is undefined).
As a Constructor
You can also invoke a function as a constructor. Based on the naming convention you're using (TestObject) this also may be what you're doing and is what's tripping you up.
You invoke a function as a Constructor with the new keyword.
function Foo(){
this.confusing = 'hell yeah';
}
var myObject = new Foo();
When invoked as a constructor, a new Object will be created, and this will be bound to that object. Again, if you have inner functions and they're used as callbacks, you'll be invoking them as functions, and this will be bound to the global object. Use that var that = this trick/pattern.
Some people think the constructor/new keyword was a bone thrown to Java/traditional OOP programmers as a way to create something similar to classes.
With the Apply Method
Finally, every function has a method (yes, functions are objects in Javascript) named "apply". Apply lets you determine what the value of this will be, and also lets you pass in an array of arguments. Here's a useless example.
function foo(a,b){
alert(a);
alert(b);
alert(this);
}
var args = ['ah','be'];
foo.apply('omg',args);
Function calls
Functions are just a type of Object.
All Function objects have call and apply methods which execute the Function object they're called on.
When called, the first argument to these methods specifies the object which will be referenced by the this keyword during execution of the Function - if it's null or undefined, the global object, window, is used for this.
Thus, calling a Function...
whereAmI = "window";
function foo()
{
return "this is " + this.whereAmI + " with " + arguments.length + " + arguments";
}
...with parentheses - foo() - is equivalent to foo.call(undefined) or foo.apply(undefined), which is effectively the same as foo.call(window) or foo.apply(window).
>>> foo()
"this is window with 0 arguments"
>>> foo.call()
"this is window with 0 arguments"
Additional arguments to call are passed as the arguments to the function call, whereas a single additional argument to apply can specify the arguments for the function call as an Array-like object.
Thus, foo(1, 2, 3) is equivalent to foo.call(null, 1, 2, 3) or foo.apply(null, [1, 2, 3]).
>>> foo(1, 2, 3)
"this is window with 3 arguments"
>>> foo.apply(null, [1, 2, 3])
"this is window with 3 arguments"
If a function is a property of an object...
var obj =
{
whereAmI: "obj",
foo: foo
};
...accessing a reference to the Function via the object and calling it with parentheses - obj.foo() - is equivalent to foo.call(obj) or foo.apply(obj).
However, functions held as properties of objects are not "bound" to those objects. As you can see in the definition of obj above, since Functions are just a type of Object, they can be referenced (and thus can be passed by reference to a Function call or returned by reference from a Function call). When a reference to a Function is passed, no additional information about where it was passed from is carried with it, which is why the following happens:
>>> baz = obj.foo;
>>> baz();
"this is window with 0 arguments"
The call to our Function reference, baz, doesn't provide any context for the call, so it's effectively the same as baz.call(undefined), so this ends up referencing window. If we want baz to know that it belongs to obj, we need to somehow provide that information when baz is called, which is where the first argument to call or apply and closures come into play.
Scope chains
function bind(func, context)
{
return function()
{
func.apply(context, arguments);
};
}
When a Function is executed, it creates a new scope and has a reference to any enclosing scope. When the anonymous function is created in the above example, it has a reference to the scope it was created in, which is bind's scope. This is known as a "closure."
[global scope (window)] - whereAmI, foo, obj, baz
|
[bind scope] - func, context
|
[anonymous scope]
When you attempt to access a variable this "scope chain" is walked to find a variable with the given name - if the current scope doesn't contain the variable, you look at the next scope in the chain, and so on until you reach the global scope. When the anonymous function is returned and bind finishes executing, the anonymous function still has a reference to bind's scope, so bind's scope doesn't "go away".
Given all the above you should now be able to understand how scope works in the following example, and why the technique for passing a function around "pre-bound" with a particular value of this it will have when it is called works:
>>> baz = bind(obj.foo, obj);
>>> baz(1, 2);
"this is obj with 2 arguments"
Is this defined behavior? Is it
cross-browser safe?
Yes. And yes.
Is there any reasoning underlying why
it is the way it is...
The meaning of this is pretty simple to deduce:
If this is used inside a constructor function, and the function was invoked with the new keyword, this refers to the object that will be created. this will continue to mean the object even in public methods.
If this is used anywhere else, including nested protected functions, it refers to the global scope (which in the case of the browser is the window object).
The second case is obviously a design flaw, but it's pretty easy to work around it by using closures.
In this case the inner this is bound to the global object instead of to the this variable of the outer function.
It's the way the language is designed.
See "JavaScript: The Good Parts" by Douglas Crockford for a good explanation.
I found a nice tutorial about the ECMAScript this
A this value is a special object which is related with the execution
context. Therefore, it may be named as a context object (i.e. an
object in which context the execution context is activated).
Any object may be used as this value of the context.
a this value is a property of the execution context, but not a
property of the variable object.
This feature is very important, because in contrary to variables, this value never participates in identifier resolution process. I.e. when accessing this in a code, its value is taken directly from the execution context and without any scope chain lookup. The value of this is determinate only once when entering the context.
In the global context, a this value is the global object itself (that means, this value here equals to variable object)
In case of a function context, this value in every single function call may be different
Reference Javascript-the-core and Chapter-3-this
All the answers here are very helpful but I still had a hard time to figure out what this point to in my case, which involved object destructuring. So I would like to add one more answer using a simplified version of my code,
let testThis = {
x: 12,
y: 20,
add({ a, b, c }) {
let d = a + b + c()
console.log(d)
},
test() {
//the result is NaN
this.add({
a: this.x,
b: this.y,
c: () => {
//this here is testThis, NOT the object literal here
return this.a + this.b
},
})
},
test2() {
//64 as expected
this.add({
a: this.x,
b: this.y,
c: () => {
return this.x + this.y
},
})
},
test3() {
//NaN
this.add({
a: this.x,
b: this.y,
c: function () {
//this here is the global object
return this.x + this.y
},
})
},
}
As here explained Javascript - destructuring object - 'this' set to global or undefined, instead of object it actually has nothing to do with object destructuring but how c() is called, but it is not easy to see through it here.
MDN says "arrow function expressions are best suited for non-method functions" but arrow function works here.
this in JS:
There are 3 types of functions where this has a different meaning. They are best explained via example:
Constructor
// In a constructor function this refers to newly created object
// Every function can be a constructor function in JavaScript e.g.
function Dog(color){
this.color = color;
}
// constructor functions are invoked by putting new in front of the function call
const myDog = new Dog('red');
// logs Dog has color red
console.log('Dog has color ' + myDog.color);
Normal function or method
// Browswer example:
console.log(this === window) // true
function myFn(){
console.log(this === window)
}
myFn(); // logs true
// The value of this depends on the context object.
// In this case the context from where the function is called is global.
// For the global context in the browser the context object is window.
const myObj = {fn: myFn}
myObj.fn() // logs false
// In this case the context from where the function is called is myObj.
// Therefore, false is logged.
myObj.fn2 = function myFn(){
console.log(this === myObj)
}
myObj.fn2() // logs true
// In this case the context from where the function is called is myObj.
// Therefore, true is logged.
Event listener
Inside the function of an event handler this will refer to the DOM element which detected the event. See this question: Using this inside an event handler

Calling a constructor function | why does "this" keyword return undefined?

I'm playing around with objects and constructors and am curious why I can't execute: person(5,10). The parameters are passed to the person function but then the variable assignment disappears and I get the "cannot set property "age" of undefined" error in chrome.
"use strict"
function person(age, height){
this.age = age;
this.height = height;
this.calculate = function(){
var newHeight = this.height * 2;
console.log(newHeight);
}
}
person(5,10);
The confusion comes because a function can be used as a callable function and an object constructor both.
Good practice is to not mix up both forms, meaning a constructor function should not be used as a callable function.
In general constructor function has first letter capitalized (just by convention to give a hint to the reader of the code).
Object based languages in general implicitly provide the reference to the object on which a method is called. In Javascript this reference is "this" keyword inside the function.
Consider the following code.
var obj = {
sum: 0,
add: function(increment) {
this.sum += increment;
return this.sum;
}
};
When we call obj.add(2), interpreter or compiler in any other object based language will do an internal calling of method add as following
add(arguments..., [this=obj]) {
//this is the obj reference inside the method
}
add(arguments, obj);
Above is just a pseudo code, last parameter is hidden from us and we don't need to pass it explicitly, this parameter is the reference to the actual object on which the add() method was invoked and is available via "this" keyworkd.
In general when we declare a function outside an Object scope, it becomes method (Edited** if not nested in another function) of the global object ( normally window object). So it's invokation will pass global object as the "this" reference. In strict mode default global object is undefined and any operations that have to be done on the window or global object are to be done explicitly. So that we do not modify the global object inadvertently.
When we call a function as a constructor like below
var p1 = new Person();
Interpreter will execute a code similar to
var newObj = new Object();
Person(arguments..., [this=newObj]) {
//this is the newObj reference inside the method
return this;
}
Person(arugments..., newObj);
I hope it's a bit clearer now.
I get the "cannot set property "age" of undefined" error in chrome.
When you call a function in strict mode, this is undefined. It seems you want to call the function as constructor, with new:
new person(5, 10)
Learn more about constructors.
Note: The convention is to capitalize the name of constructor functions.

Does ES5's "use strict"; influence closure?

If I am not wrong, under strict mode, functions don't get access to global object (The 'this' is undefined for the function). On the other hand, inner function need access to its parent's 'this' for closure to work. Does JavaScript make an exception for inner functions under strict mode?
Closures have nothing to do with the this pointer. Closures are a concept of functional programming not object oriented programming. The this pointer is a concept of object oriented programming. Both can work simultaneously and independently without causing problems.
For example consider the following function in strict mode:
function getCounter() {
"use strict";
var count = 0;
return function counter() {
return ++count;
};
}
Here a call to the getCounter returns a closure. The function counter closes over the value count. You can then use the returned counter as follows:
var counter = getCounter();
counter(); // 1
counter(); // 2
counter(); // 3
I think you're confusing closures with nested functions. Read the following thread. It explains closures really well: JavaScript closures vs. anonymous functions
In strict mode the this pointer is undefined when it would point to the global object. Otherwise you may use it normally. This prevents you from accidentally creating global variables. However it doesn't cause any hinderance.
Consider the following constructor function for example:
function Counter() {
"use strict";
var count = 0;
this.increment = function () {
count++;
};
this.getCount = function () {
return count;
};
}
You can create an instance and use it as follows:
var counter = new Counter;
counter.increment();
counter.getCount(); // 1
However if you forget to put the new then this will point to the global object which in strict mode is undefined. Hence trying to assign the method increment to this will throw an error.
Getting back to the original question, you can always store the value of the this pointer in another variable if you wish to access it in a nested function. For example:
function Counter() {
"use strict";
var that = this;
that.count = 0;
return function counter() {
return ++that.count;
};
}
I know that this is a really stupid example but it has all the elements required to get my point across. You can now use the above function as follows:
var counter = new Counter;
counter(); // 1
counter(); // 2
counter(); // 3
That's all that there is to it.
By your question, I believe you meant Constructors and instanced objects. use strict pragma does not affect it. Accessing and calling an object's property of type function through dot or square brackets notation inside an expression automatically sets the ThisBinding to the object from which you got the function reference.
function Foo() {}
Foo.prototype.someMethod = function() {
console.log(this.blah);
};
var foo = new Foo();
foo.blah = 1;
//this:
foo.someMethod();
//implicitly does this:
foo.someMethod.call(foo);
Fiddle
TJ has probably explained this behavior in a simpler manner in Mythical Methods:
[...] when you call a function using an expression that gets the function reference from an object property (e.g., object.functionName() or object['functionName']()), the object is set automatically as "this" within the function call.
use strict only makes a difference when the this binding is not set (null or undefined), which is not the case here.
Then as you know, when the this reference is not set when entering function code, in non-strict mode it refers to the global object (the window object in browser environment) while in strict mode it is undefined. See ES5.1 Section 10.4.3
Now if you mean closures as in a function inside of another, use the old lexical scope trick.
function outerFunction() {
var _this = this;
function innerFunction() {
// _this references the outerFunction's this
}
}
This behavior is not influenced by use strict either.

JavaScript losing "this" object reference with private/public properties

I have the following error when running the page below:
"this.testpublic is not a function"
test = function() {
var testprivate = function() {
this.testpublic();
}
this.testpublic = function() {
console.log('test');
}
testprivate();
}
new test();
Apparently when testprivate is called, "this" starts pointing to "window" instead of the object.
Shouldn't JavaScript preserve "this" context when within the same object?
You need to manipulate the context when calling testprivate. You can use function.call to override the scope of the function. Try this:
test = function() {
var testprivate = function() {
this.testpublic();
}
this.testpublic = function() {
console.log('test');
}
testprivate.call(this);
}
new test();
The problem is that this actually never was referring to the test object to begin with. It was always referring to the nearest enclosing object -- which in this case is window.
test = function() {
var testprivate = function(say) {
console.log('test', say);
}
this.testpublic = function(say) {
testprivate('test', say);
}
testprivate();
}
x = new test();
This works because, as I understand it, this is determined at call time -- and it is locked into the nearest "enclosing" object*, unless call() or apply() is used.
* There is probably a much better word for this, but I don't know it off the top of my head. If someone knows, please enlighten us all :-)
No, it shouldn't. The function merely defines scope.
When you call foo.bar() then this (inside bar()) is foo. Since there is no explicit foo in this case, it is window by default.
(this is handled differently when the new keyword is in play, but it isn't for that call)
It is as Sean says: you aren't actually creating a new reference to an object (creating a this context), because you are simply calling the constructor - not utilizing the constructor to create a new object. If you use the new keyword, it works just peachy.
Since the scope of test() is window when you call it, any function called from within test() will execute in the window scope.
By using the new keyword, you are allocating a new object to memory - and creating a new scope.
For example, try this in firebug:
var myFunction = function() {
this.memberVariable = "foo";
console.log(this);
}
myFunction();
console.log(window.memberVariable);
var myObject = new myFunction();
console.log(myObject.memberVariable);
You will see this result:
Window stats
foo
Object { memberVariable="foo"}
foo
The Function base object has a method, call(), which as outlined by Craig, allows you to explicitly specify which scope the function should run in:
var myFunction = function() {
this.memberVariable = "foo";
}
myFunction.call(myFunction);
console.log(myFunction); // "Function()"
console.log(myFunction.memberVariable); // "foo"
This is, however, not the preferred way of doing things, as you aren't actually creating a new object here, and typeof myFunction will still return "function" instead of "object" - when you really just wanted to create an object.

Categories