I have read over some rules to determine what the value of this is in different scenarios in Javascript. All was well till the example below threw me off.
function Person(name){
this.name = name; //this is the object when function used as constructor (as expected)
this.changeName = someFunction(); // produces error
function someFunction(){
this.nickName = this.name+"by"; //this is now the global object and not the instance, thus the name property does not exist.
}
}
var a = new Person ('bob'); //error due to the function in changeName property.
From what I understood, the this variable takes up the value of the invoking object when called through dot notation or takes up the value of the newly constructed function when used with the new key word.
Can someone explain why the this statement in the function above is the global objet and not the newly instantiated object?
Can someone explain why the this statement in the function above is the global objet and not the newly instantiated object?
Because when you call a(n unbound) function as func(), this will refer to the global object (or undefined if the function is in strict mode).
Every function (except arrow functions) has its own this value. So the fact that you are calling Person as new Person() and that this inside Person refers to a new object, doesn't have any impact on the this value in someFunction. It only matters how you can someFunction.
You could call someFunction and explicitly set its this value via .call:
this.changeName = someFunction.call(this);
See also: How to access the correct `this` inside a callback?
The this within someFunction() will reference a global object, because it's inside a function call. See a fuller, much more complete explanation at How does "this" keyword work within a function?
If you wish to solve the issue, alias this inside the parent.
function Person(name){
var self = this; // Store a reference to the current instance
self.name = name;
self.changeName = someFunction(); // Odd that you'd capture the return value of a setter, ...
function someFunction(){
self.nickName = self.name+"by"; //self references the instance, creating the property.
}
}
Related
Below I am creating an object in JavaScript. Within the constructor I am setting up an event listener. The problem is that when the event gets fired, this.prop cannot be found, and undefined prints out. How do I solve this?
var someObj = function someObj(){
this.prop = 33;
this.mouseMoving = function() { console.log(this.prop);}
document.getElementById("someDiv").addEventListener('mousemove', this.mouseMoving, true);
}
When the event handler gets called, "this" no longer references the "someObj" object. You need to capture "this" into a local variable that the mouseMoving function will capture.
var someObj = function someObj(){
this.prop = 33;
var self = this;
this.mouseMoving = function() { console.log(self.prop);}
document.getElementById("someDiv").addEventListener('mousemove', this.mouseMoving, true);
}
I'm assuming "someObj is a constructor, i.e. intended to be called with as new someObj(), otherwise "this" will be the global scope.
The "this" keyword can be confusing in JavaScript, because it doesn't work the same way as in other languages. The key thing to remember is that it is bound to the calling object when the function is called, not when the function is created.
The javascript built-in Function.prototype.bind() is intended for this purpose.
For example:
var someObj = function someObj(){
this.prop = 33;
this.mouseMoving = function() { console.log(this.prop);}
document.getElementById("someDiv").addEventListener('mousemove', this.mouseMoving.bind(this),true);
}
More on the bind method here: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind
Other wise you have to pass a reference of the object someObj to the element and use that reference in the line:
console.log(this.referenceToObject.prop); //this references the DOM element in an event.
From Section 4.3 of JavaScript: The Good Parts by Douglas Crockford:
Invoking a function suspends the
execution of the current function,
passing control and parameters to the
new function. In addition to the
declared parameters, every function
receives two additional parameters:
this and arguments. The this parameter
is very important in object oriented
programming, and its value is
determined by the invocation pattern.
There are four patterns of invocation
in JavaScript: the method invocation
pattern, the function invocation
pattern, the constructor invocation
pattern, and the apply invocation
pattern. The patterns differ in how
the bonus parameter this is
initialized.
Crockford continues to explains the binding of 'this' in each of these patterns, as follows:
The Method Invocation Pattern:
When a function is stored as a property of an object, we call it a method. When a method is invoked, this is bound to that object.
The Function Invocation Pattern:
When a function is invoked with this pattern, this is bound to the global object. This was a mistake in the design of the language.
The Constructor Invocation Pattern:
If a function is invoked with the new prefix, then a new object will be created with a hidden link to the value of the function's prototype member, and this will be bound to that new object.
The Apply Invocation Pattern:
The apply method lets us construct an array of arguments to use to invoke a function. It also lets us choose the value of this. The apply method takes two parameters. The first is the value that should be bound to this. The second is an array of parameters.
You could use a variable named 'me', to avoid conflict with the global JavaScript variable 'self':
function someObj() {
var me = this;
this.prop = 33;
this.mouseMoving = function() {
alert(me.prop);
}
document.getElementById("someDiv").addEventListener('mousemove', this.mouseMoving, true);
}
First, you need to understand how 'this' works in JavaScript. 'this' keyword doesn't behave how it behaves in other languages like C# or Java. Read following post to understand more,
What is the rationale for the behavior of the 'this' keyword in JavaScript?
Once you understand that, as Matthew outlined in his code, you can save reference to 'this' and use that reference inside the mouseMoving function.
Though overall, I will advise that you use a JavaScript framework (e.g. jQuery, YUI, MooTools) which will take care of these issues for you. E.g. In Internet Explorer, you use addEvent to attach event and not addEventListenr.
You have some typos on your function declaration.
Your prop variable is also defined as a "public" or "visible" member (by using this.prop), doing so forces you to store the reference of this from the outer function (that is actually a reference to the object instance), as a "private" member of the function (using var) to get access the instance of the created object and read the "public" prop member.
You have some alternatives to rewrite this code:
function someObj (){
var self = this;
this.prop = 33;
this.mouseMoving = function() { alert(self.prop);} // You access the current
// instance, stored in *self*
// since *this*, inside the
// function, is in another
// context.
//...
}
var mySomeObj = new someObj(); // Object instantiation
Or you could:
function someObj (){
var prop = 33;
this.mouseMoving = function() { alert(prop);}
//...
}
var mySomeObj = new someObj(); // Object instantiation
The variables declared with var, are accesible to the functions declared inside of the major constructor function, this feature is known as Closures.
Below I am creating an object in JavaScript. Within the constructor I am setting up an event listener. The problem is that when the event gets fired, this.prop cannot be found, and undefined prints out. How do I solve this?
var someObj = function someObj(){
this.prop = 33;
this.mouseMoving = function() { console.log(this.prop);}
document.getElementById("someDiv").addEventListener('mousemove', this.mouseMoving, true);
}
When the event handler gets called, "this" no longer references the "someObj" object. You need to capture "this" into a local variable that the mouseMoving function will capture.
var someObj = function someObj(){
this.prop = 33;
var self = this;
this.mouseMoving = function() { console.log(self.prop);}
document.getElementById("someDiv").addEventListener('mousemove', this.mouseMoving, true);
}
I'm assuming "someObj is a constructor, i.e. intended to be called with as new someObj(), otherwise "this" will be the global scope.
The "this" keyword can be confusing in JavaScript, because it doesn't work the same way as in other languages. The key thing to remember is that it is bound to the calling object when the function is called, not when the function is created.
The javascript built-in Function.prototype.bind() is intended for this purpose.
For example:
var someObj = function someObj(){
this.prop = 33;
this.mouseMoving = function() { console.log(this.prop);}
document.getElementById("someDiv").addEventListener('mousemove', this.mouseMoving.bind(this),true);
}
More on the bind method here: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind
Other wise you have to pass a reference of the object someObj to the element and use that reference in the line:
console.log(this.referenceToObject.prop); //this references the DOM element in an event.
From Section 4.3 of JavaScript: The Good Parts by Douglas Crockford:
Invoking a function suspends the
execution of the current function,
passing control and parameters to the
new function. In addition to the
declared parameters, every function
receives two additional parameters:
this and arguments. The this parameter
is very important in object oriented
programming, and its value is
determined by the invocation pattern.
There are four patterns of invocation
in JavaScript: the method invocation
pattern, the function invocation
pattern, the constructor invocation
pattern, and the apply invocation
pattern. The patterns differ in how
the bonus parameter this is
initialized.
Crockford continues to explains the binding of 'this' in each of these patterns, as follows:
The Method Invocation Pattern:
When a function is stored as a property of an object, we call it a method. When a method is invoked, this is bound to that object.
The Function Invocation Pattern:
When a function is invoked with this pattern, this is bound to the global object. This was a mistake in the design of the language.
The Constructor Invocation Pattern:
If a function is invoked with the new prefix, then a new object will be created with a hidden link to the value of the function's prototype member, and this will be bound to that new object.
The Apply Invocation Pattern:
The apply method lets us construct an array of arguments to use to invoke a function. It also lets us choose the value of this. The apply method takes two parameters. The first is the value that should be bound to this. The second is an array of parameters.
You could use a variable named 'me', to avoid conflict with the global JavaScript variable 'self':
function someObj() {
var me = this;
this.prop = 33;
this.mouseMoving = function() {
alert(me.prop);
}
document.getElementById("someDiv").addEventListener('mousemove', this.mouseMoving, true);
}
First, you need to understand how 'this' works in JavaScript. 'this' keyword doesn't behave how it behaves in other languages like C# or Java. Read following post to understand more,
What is the rationale for the behavior of the 'this' keyword in JavaScript?
Once you understand that, as Matthew outlined in his code, you can save reference to 'this' and use that reference inside the mouseMoving function.
Though overall, I will advise that you use a JavaScript framework (e.g. jQuery, YUI, MooTools) which will take care of these issues for you. E.g. In Internet Explorer, you use addEvent to attach event and not addEventListenr.
You have some typos on your function declaration.
Your prop variable is also defined as a "public" or "visible" member (by using this.prop), doing so forces you to store the reference of this from the outer function (that is actually a reference to the object instance), as a "private" member of the function (using var) to get access the instance of the created object and read the "public" prop member.
You have some alternatives to rewrite this code:
function someObj (){
var self = this;
this.prop = 33;
this.mouseMoving = function() { alert(self.prop);} // You access the current
// instance, stored in *self*
// since *this*, inside the
// function, is in another
// context.
//...
}
var mySomeObj = new someObj(); // Object instantiation
Or you could:
function someObj (){
var prop = 33;
this.mouseMoving = function() { alert(prop);}
//...
}
var mySomeObj = new someObj(); // Object instantiation
The variables declared with var, are accesible to the functions declared inside of the major constructor function, this feature is known as Closures.
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.
First post. New to programming.
In Javascript, when I declare a new variable and also set this newly declared variable to store a function, is that function immediately executed when the code runs (execution context)?
For instance,
function Person() {
console.log(this);
this.firstname = 'John';
this.lastname = 'Doe';
}
var john = new Person();
Is the variable john being declared at the same time the function "Person" is being executed on that same line?
What you copy/paste is an object creation. It means john is a new Person object. Person being the class of the object. The this keywork in your Person function is related to the instance of the newly created object. Don't be abused by the function keyword, which is a confusing (because of historical reason) JS keyword. Person function can be seen as an object constructor.
EDIT : removed the off topic remark (really too much off topic)
var john = new Person();
Variable john is created.
RHS is executed.
2.1. new operator calls the contructor of the Person. Every function implictly has a constructor(). This results in Object creation.
Result of RHS evaluation is returned (which is an object in this case).
Result is assigned to john or in other words, now john (a reference variable) will refer to the object which was created as a result of new operator executed on Person().
If you put () or (optionalArgumentsHere) (some functions take arguments, some don't) after a function it means it is a function call, and it will be executed. If you want to assign the function itself to a variable, you need to omit the (). It is possible because functions are objects in JavaScript (which is not true in every language).
So what happens here is that you declare a variable (you actually declare it earlier because of hoisting, as explained by Pablo), you execute new Person() and assign the result to the variable.
If you called some function like
function fun() {
return 5;
}
var x = fun();
You would be assigning the return value of the function to the variable. But your case is special, because you use new. That means Person is a constructor, and it is used to create a new object of type Person. Inside that constructor, you use the this keyword to attach properties to the newly created object. The new Person() call returns the object, even though return is not called explicitly.
In Javascript, variable definitions are "hoisted". It means that the code that you posted and the following one...
var john;
function Person() {
console.log(this);
this.firstname = 'John';
this.lastname = 'Doe';
}
john = new Person();
... are identical, because the compiler will hoist the variable declaration to the beginning of the current context. So, the answer is no, the variable is declared, then the function is executed as a constructor, and then the new creadted object is assigned to that variable.
You can find more information here
Most of us know that JavaScript has no sense of "private" properties, but that behavior can be emulated through the use of closures:
var Car = function () {
var name = 'Tesla';
var wheelCount = 4;
this.getName = function () {
return name;
};
this.getWheelCount = function () {
return wheelCount;
};
this.setName = function (newName) {
name = newName;
};
this.setWheelCount = function (newCount) {
wheelCount = newCount;
};
};
var myCar = new Car();
console.log(myCar.name); // undefined
That all makes sense to us that know about how JavaScript closures work. However, the following will work:
myCar.name = 'Corvette';
console.log(myCar.name); // 'Corvette'
But then if you call the function from the prototype, the enclosed variable is still used
console.log(myCar.getName()); // 'Tesla'
When you call myCar.name, you're adding a new property to the object. Is it just the entire point of using this when declaring the getName (etc) functions inside the Car definition to make the differentiation between the enclosed name inside the Car declaration versus the myCar.name?
I have a feeling that I know the answer to this, but I would like to be certain. Plus, I think this would be something invaluable to other people getting an advanced grasp on how JavaScript enclosures work.
Is it just the entire point of using this when declaring the getName (etc) functions inside the Car definition to make the differentiation between the enclosed name inside the Car declaration versus the myCar.name?
Yes.
this (or myCar) is the object, on which you put the properties that you want to have it (in this case all those methods). If you want to use properties, you must use a property accessor.
var name is just a local variable in the constructor function, which is accessed by closure from the object's methods.
Or, to answer your title question:
If a variable is enclosed, and an instance sets a property with the same name, where does the property go?
The property goes on the object. It doesn't interfere at all with the variable, which is located in the scope of the Car constructor invocation.
In your example car function is a constructor function. When a constructor function is called with new operator, a new object is created and "this" gets bound to that new object. And "this" is returned from the function even if there is no return statement (unlike non-constructor functions that returns undefined if nothing is returned)
So When you called new Car() a new object got created and as "this" was bounded to this new object, the new object got 4 functions that you defined in Car function (getName, getWheelCount, setName, setWheelCount)
The name variable defined in Car function is not bounded to "this", it is bounded to Car's function scope. When car function returned "this", because of closure getName() still has access to function's name variable.
Now when you tried myCar.name, as the new object that was created does not have any variable called name, it printed undefined.
On doing myCar.name = 'Corvette', as no property named name was found in myCar,new property was created with name "name" and value "Corvette" (javascript creates a new property if it is not already existing in case of write operations, for read operations prototype chain is followed)
But surprisingly myCar.getName() still prints "Tesla" and not Corvette, because though the variable names are same they are in diffrent scope.The one that is referred by getName was part of Car function scope and is bounded to getName via Closure, but the name ("corvette") that you added belongs to new object that you created.
The purpose of "this" is to add the functions/variables defined inside constructor function to the object that you are going to create through that constructor function.
Hope it helps.