I must confess, JavaScript has -sometimes- strange behaviors.
var Npc = function() {
this.name='Hello world';
}
Npc.attr='my new attribute';
console.log('>>>>'+Npc.attr); // my new attribute
console.log('>>>>'+Npc.name); // '' ????
var data = new Npc();
console.log('>>>>>' + data.attr); // undefined
console.log('>>>>>' + data.name); // Hello world
Sounds weird to me.
If I can understand the .name difference (instance vs literal), I cannot understand the "attr" behavior.
Is it a COW ? But with the node.js debugger I really see the attr atribute !?
Waw...
It's perfectly normal.
var Npc = function() {
this.name='Hello world';
}
is a function constructor,until you execute the function nothing happens and name doesnt exist,makes sense.
so at this point only attr is defined.
var data = new Npc();
console.log('>>>>>' + data.attr); // undefined
console.log('>>>>>' + data.name);
var data = new Npc(); returns a new object, makes sense because you are using new.
if you want to access attr you need to find a reference to Npc inside that new object
data.constructor.attr is where you will find attr
Edit
little mistake on data.constructor.attr corrected
If you're coming from a class-keyword language like Java or C++, then this might help you.
In JavaScript a function can be used as a constructor for an object, as you did here:
var Npc = function() {
this.name='Hello world';
}
var data = new Npc();
By way of loose analogy to a class-keyword language, the "name" property is an instance variable defined in a "class" called Npc. So the expression data.name is perfectly logical.
In JavaScript a function is also an object, which is how you used it here:
Npc.attr='my new attribute';
Again by way of loose analogy to a class-keyword language, Npc.attr is like a static class member. So attr is a member of Npc and not a member of any instance of Npc.
Nothing strange here.
attr is the attribute of Npc function.
name is the attribute of object created when Npc is used as a constructor.
Therefore Npc function has no attribute name and object created by Npc has no attribute attr.
Don't confuse constructor function with objects it produces. If you want property to automatically propagate to all created objects - prototype it:
Npc.prototype.attr='my new attribute';
var data = new Npc();
console.log('>>>>>' + data.attr); // 'my new attribute';
In your 1st call you call Npc() directly (i.e not as a constructor). In this case the this inside the body of the function refers to the global object, which in your browser is the window object and in node is the global object. Either way, you assigned the .name property to the global object and thus you cannot see it as a property of the function object (don't forget that functions are ordinary objects as well in JavaScript and unless used with the new operator, they are not constructors)
In the 2nd case you actually use the function as a constructor since you use it in conjunction with the new operator. Here the this.name=... inside the body actually adds a name property to the newly instantiated object of type Npc. It is the magic of the new operator that gives the meaning of "the instantiated object" to the "this" keyword in the 2nd case.
Related
Let us say we have a function.
function Rabbit(){
console.log("shiv");
}
Now without creating an object of this function i can assign the property of this object
Rabbit.bark = function(line) {
console.log("name is", line);
};
What does this mean. do this add a variable bark to function. or does this add a property to Rabbit object, even if I am not creating an object using the new operator.
Function in JavaScript is just an object, it is called Function object.
And just like any other types of object, it has its own constructor (new Function(...)), methods (apply, bind, call...) and properties (arguments, caller, name...) . See the document.
You might be familiar with creating a function like this:
function Rabbit() {
console.log('shiv');
}
Then you should know that you can also create a function like this:
var Rabbit = new Function('console.log("shiv")');
Now, you might guess it out. If you add a new property to a Function object, as long as you don't overwrite the existing one, the function is still working just fine.
do this add a variable bark to function
No, the function has it own closure, the only way to add variable to the function is to bind it to this object using Rabbit.bind(object)
do this added a property to Rabbit object
Well, since the "Rabbit object" is just an object, Yes.
what does this mean. do this add a variable bark to function. or do
this added a property to Rabbit object
do this add a variable bark to function - No
or do this added a property to Rabbit object - Yes
bark is a property of object of type Function
even if i am not creating an object using new operator
Rabit is already an object (of type Function). You are not creating an instance of this object, just that you are adding a property to it.
Let us say we have a function.
function Rabbit(){
console.log("shiv");
}
Now without creating an object of this function i can assign the property of this object
Rabbit.bark = function(line) {
console.log("name is", line);
};
What does this mean. do this add a variable bark to function. or does this add a property to Rabbit object, even if I am not creating an object using the new operator.
Function in JavaScript is just an object, it is called Function object.
And just like any other types of object, it has its own constructor (new Function(...)), methods (apply, bind, call...) and properties (arguments, caller, name...) . See the document.
You might be familiar with creating a function like this:
function Rabbit() {
console.log('shiv');
}
Then you should know that you can also create a function like this:
var Rabbit = new Function('console.log("shiv")');
Now, you might guess it out. If you add a new property to a Function object, as long as you don't overwrite the existing one, the function is still working just fine.
do this add a variable bark to function
No, the function has it own closure, the only way to add variable to the function is to bind it to this object using Rabbit.bind(object)
do this added a property to Rabbit object
Well, since the "Rabbit object" is just an object, Yes.
what does this mean. do this add a variable bark to function. or do
this added a property to Rabbit object
do this add a variable bark to function - No
or do this added a property to Rabbit object - Yes
bark is a property of object of type Function
even if i am not creating an object using new operator
Rabit is already an object (of type Function). You are not creating an instance of this object, just that you are adding a property to it.
In javascript whats the difference when i create a variable in object like below 2 ways
user.name = 'hello';
user.prototype.name = 'hello';
Fundamentally, there isn't any, in that in both cases you're creating or modifying a property on an object. But the effect of creating/modifying that property can be significant.
First, note that user will only have a property called prototype if it's a function* (or if you've created one on another kind of object). I'm going to assume that user is a function for the remainder of this answer. And since we're using user as a constructor, I'll use User instead for the rest of this answer as the overwhelming convention in JavaScript is that the names of constructor functions start with an uppercase character.
User.prototype is used if you create objects via new User. In that case, the object that User.prototype refers to will be used as the new object's prototype. That means that if you try to retrieve the value of a property on that new object and the object doesn't have a property with the given name, the JavaScript engine will look at the object's prototype to try to find it.
So adding or modifying a property on User.prototype may seem to add it to objects you've created via new User:
function User() {
}
var u1 = new User();
console.log(u1.name); // undefined
User.prototype.name = "hello";
console.log(u1.name); // "hello"
It hasn't actually been added to u1, it's just that since u1 doesn't have its own name property, when we look up name on it, the property from its prototype is used instead.
To further understand the relationship between a function's prototype property and the prototype of an object, see __proto__ VS. prototype in JavaScript.
* It needs to be a function created via the function or class keyword to have a prototype property by default; arrow functions, async functions, and methods don't have prototype by default and cannot be used as constructor functions.
First scenario:
user.name = 'hello'
if you have created an object like this:
var user = { id:'abc'};
and then you do user.name = 'hello', will simply add a property to the user object as
user{name:'hello',id:'abc'}
Second scenario:
user.prototype.name = 'hello';
if you have created an object using constructor;
eg;
function User(id) {
this.id = id;// creating an object which will differ in id;
}
now:
user.prototype.name ='hello';
will initialize any instance of user with the name as hello. We use prototype when we want the instances to have the same property and has only one copy in case of methods.
eg
var newUser = new user('id');
now newUser will be -
newUser{id:'id',name:'hello'}
Let us say we have a function.
function Rabbit(){
console.log("shiv");
}
Now without creating an object of this function i can assign the property of this object
Rabbit.bark = function(line) {
console.log("name is", line);
};
What does this mean. do this add a variable bark to function. or does this add a property to Rabbit object, even if I am not creating an object using the new operator.
Function in JavaScript is just an object, it is called Function object.
And just like any other types of object, it has its own constructor (new Function(...)), methods (apply, bind, call...) and properties (arguments, caller, name...) . See the document.
You might be familiar with creating a function like this:
function Rabbit() {
console.log('shiv');
}
Then you should know that you can also create a function like this:
var Rabbit = new Function('console.log("shiv")');
Now, you might guess it out. If you add a new property to a Function object, as long as you don't overwrite the existing one, the function is still working just fine.
do this add a variable bark to function
No, the function has it own closure, the only way to add variable to the function is to bind it to this object using Rabbit.bind(object)
do this added a property to Rabbit object
Well, since the "Rabbit object" is just an object, Yes.
what does this mean. do this add a variable bark to function. or do
this added a property to Rabbit object
do this add a variable bark to function - No
or do this added a property to Rabbit object - Yes
bark is a property of object of type Function
even if i am not creating an object using new operator
Rabit is already an object (of type Function). You are not creating an instance of this object, just that you are adding a property to it.
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.