What's the difference between
var A = function () {
this.x = function () {
//do something
};
};
and
var A = function () { };
A.prototype.x = function () {
//do something
};
What's the difference between
var A = function () {
this.x = function () {
//do something
};
};
and
var A = function () { };
A.prototype.x = function () {
//do something
};
The first example changes the interface for that object only. The second example changes the interface for all object of that class.
In most cases they are essentially the same, but the second version saves memory because there is only one instance of the function instead of a separate function for each object.
A reason to use the first form is to access "private members". For example:
Because of javascript's scoping rules, private_var is available to the function assigned to this.x, but not outside the object.
The ultimate problem with using
this
instead ofprototype
is that when overriding a method, the constructor of the base class will still refer to the overridden method. Consider this:versus:
If you think this is not a problem, then it depends on whether you can live without private variables, and whether you are experienced enough to know a leak when you see one. Also, having to put the constructor logic after the method definitions is inconvenient.
versus:
Take these 2 examples:
vs.
Most people here (especially the top-rated answers) tried to explain how they are different without explaining WHY. I think this is wrong and if you understand the fundamentals first, the difference will become obvious. Let's try to explain the fundamentals first...
a) A function is an object in JavaScript. EVERY object in JavaScript gets an internal property (meaning, you can't access it like other properties, except maybe in browsers like Chrome), often referred to as
__proto__
(you can actually typeanyObject.__proto__
in Chrome to see what it references. This is just that, a property, nothing more. A property in JavaScript = a variable inside an object, nothing more. What do variables do? They point to things.So what does this
__proto__
property points to? Well, usually another object (we'll explain why later). The only way to force JavaScript for the__proto__
property to NOT point to another object is to usevar newObj = Object.create(null)
. Even if you do this, the__proto__
property STILL exists as a property of the object, just it doesn't point to another object, it points tonull
.Here's where most people get confused:
When you create a new function in JavaScript (which is an object as well, remember?), the moment it is defined, JavaScript automatically creates a new property on that function called
prototype
. Try it:A.prototype
is TOTALLY DIFFERENT from the__proto__
property. In our example, 'A' now has TWO properties called 'prototype' and__proto__
. This is a big confusion for people.prototype
and__proto__
properties are in no way related, they're separate things pointing to separate values.You may wonder: Why does JavaScript has
__proto__
property created on every single object? Well, one word: delegation. When you call a property on an object and the object doesn't have it, then JavaScript looks for the object referenced by__proto__
to see if it maybe has it. If it doesn't have it, then it looks at that object's__proto__
property and so on...until the chain ends. Thus the name prototype chain. Of course, if__proto__
doesn't point to an object and instead points tonull
, well tough luck, JavaScript realizes that and will return youundefined
for the property.You may also wonder, why does JavaScript creates a property called
prototype
for a function when you define the function? Because it tries to fool you, yes fool you that it works like class-based languages.Let's go on with our example and create an "object" out of
A
:There's something happening in the background when this thing happened.
a1
is an ordinary variable which was assigned a new, empty object.The fact that you used the operator
new
before a function invocationA()
did something ADDITIONAL in the background. Thenew
keyword created a new object which now referencesa1
and that object is empty. Here's what happening additionally:We said that on each function definition there's a new property created called
prototype
(which you can access it, unlike with the__proto__
property) created? Well, that property is being used now.So we're now at the point where we have a freshly baked empty
a1
object. We said that all objects in JavaScript have an internal__proto__
property which points to something (a1
also has it), whether it's null or another object. What thenew
operator does is that it sets that__proto__
property to point to the function'sprototype
property. Read that again. It's basically this:We said that
A.prototype
is nothing more than an empty object (unless we change it to something else before defininga1
). So now basicallya1.__proto__
points to the same thingA.prototype
points to, which is that empty object. They both point to the same object which was created when this line happened:Now, there's another thing happening when
var a1 = new A()
statement is processed. BasicallyA()
is executed and if A is something like this:All that stuff inside
function() { }
is going to execute. When you reach thethis.hey..
line,this
is changed toa1
and you get this:I won't cover why
this
changes toa1
but this is a great answer to learn more.So to summarize, when you do ``var a1 = new A()` there are 3 things happening in the background:
a1
.a1 = {}
a1.__proto__
property is assigned to point at the same thing asA.prototype
points to (another empty object {} )The function
A()
is being executed withthis
set to the new, empty object created in step 1 (read the answer I referenced above as to whythis
changes toa1
)Now, let's try to create another object:
Steps 1,2,3 will repeat. Do you notice something? The key word is repeat. Step 1:
a2
will be a new empty object, step 2: its__proto__
property will point to the same thingA.prototype
points to and most importantly, step 3: functionA()
is AGAIN executed, which means thata2
will gethey
property containing a function.a1
anda2
have two SEPARATE properties namedhey
which point to 2 SEPARATE functions! We now have duplicate functions in same two different objects doing the same thing, oops...You can imagine the memory implications of this if we have 1000 objects created withnew A
, after all functions declarations take more memory than something like the number 2. So how do we prevent this?Remember why the
__proto__
property exists on every object? So that if you retrieve theyoMan
property ona1
(which doesn't exist), its__proto__
property will be consulted, which if it's an object (and is most cases it is), it will check if it containsyoMan
, and if it doesn't, it will consult that object's__proto__
etc. If it does, it will take that property value and display it to you.So someone decided to use this fact + the fact that when you create
a1
, its__proto__
property points to the same (empty) objectA.prototype
points to and do this:Cool! Now, when you create
a1
, it again goes through all of the 3 steps above, and in step 3, it doesn't do anything, sincefunction A()
has nothing to execute. And if we do:It will see that
a1
does not containhey
and it will check its__proto__
property object to see if it has it, which is the case.With this approach we eliminate the part from step 3 where functions are duplicated on each new object creation. Instead of
a1
anda2
having a separatehey
property, now NONE of them has it. Which, I guess, you figured out yourself by now. That's the nice thing...if you understand__proto__
andFunction.prototype
, questions like these will be pretty obvious.NOTE: Some people tend to not call the internal Prototype property as
__proto__
, I've used this name through the post to distinguish it clearly to theFunctional.prototype
property as two different things.Every object is linked to a prototype object. When trying to access a property that does not exist, JavaScript will look in the object's prototype object for that property and return it if it exists.
The
prototype
property of a function constructor refers to the prototype object of all instances created with that function when usingnew
.In your first example, you are adding a property
x
to each instance created with theA
function.In the second example you are adding a property to the prototype object that all the instances created with
A
point to.In conclusion, in the first example a copy of the function is assigned to each instance. In the second example a single copy of the function is shared by all instances.
The examples have very different outcomes.
Before looking at the differences, the following should be noted:
[[Prototype]]
property.myObj.method()
) then this within the method references the object. Where this is not set by the call or by the use of bind, it defaults to the global object (window in a browser) or in strict mode, remains undefined.So here are the snippets in question:
In this case, variable
A
is assigned a value that is a reference to a function. When that function is called usingA()
, the function's this isn't set by the call so it defaults to the global object and the expressionthis.x
is effectivewindow.x
. The result is that a reference to the function expression on the right-hand side is assigned towindow.x
.In the case of:
something very different occurs. In the first line, variable
A
is assigned a reference to a function. In JavaScript, all functions objects have a prototype property by default so there is no separate code to create an A.prototype object.In the second line, A.prototype.x is assigned a reference to a function. This will create an x property if it doesn't exist, or assign a new value if it does. So the difference with the first example in which object's x property is involved in the expression.
Another example is below. It's similar to the first one (and maybe what you meant to ask about):
In this example, the
new
operator has been added before the function expression so that the function is called as a constructor. When called withnew
, the function's this is set to reference a new Object whose private[[Prototype]]
property is set to reference the constructor's public prototype. So in the assignment statement, thex
property will be created on this new object. When called as a constructor, a function returns its this object by default, so there is no need for a separatereturn this;
statement.To check that A has an x property:
This is an uncommon use of new since the only way to reference the constructor is via A.constructor. It would be much more common to do:
Another way of achieving a similar result is to use an immediately invoked function expression:
In this case,
A
assigned the return value of calling the function on the right-hand side. Here again, since this is not set in the call, it will reference the global object andthis.x
is effectivewindow.x
. Since the function doesn't return anything,A
will have a value ofundefined
.These differences between the two approaches also manifest if you're serializing and de-serializing your Javascript objects to/from JSON. Methods defined on an object's prototype are not serialized when you serialize the object, which can be convenient when for example you want to serialize just the data portions of an object, but not it's methods:
Related questions:
Sidenote: There may not be any significant memory savings between the two approaches, however using the prototype to share methods and properties will likely use less memory than each instance having its own copy.
JavaScript isn't a low-level language. It may not be very valuable to think of prototyping or other inheritance patterns as a way to explicitly change the way memory is allocated.