I have read through some tutorials about javascript prototypal inheritance patterns but I am not sure which is the best practice out of the following two. I noted that many people do this inheritance pattern:
var A = function (){}
A.prototype = {}
var B = function () {
A.apply(this, arguments); // Calling the constructor of A
}
B.prototype = new A(); // Inherit from A through an instance
Alternative, there are some sources that do the following pattern instead:
var A = function (){}
A.prototype = {}
var B = function () {
A.apply(this, arguments); // Calling the constructor of A
}
for (var prop in A.prototype) {
B.prototype[prop] = A.prototype[prop]; // Inherit from A by copying every property/methods from A
}
Although both patterns work, I rarely see people use the latter inheritance pattern (ie. copying each property/methods from the parent's prototype) - why? Is there something wrong with copying properties/methods directly from parent to child? Also, are these two patterns intrinsically different in some ways?
Thank you.
These patterns are very different, and as you may have guessed, the first is better (but not the best possible). Let us compare:
The Most Modern, Best Pattern
B.prototype = Object.create(A.prototype);
This uses the Object.create function to set B.prototype to a new object, whose internal [[Prototype]] is A.prototype. This is basically exactly what you want: it will make B instances delegate to A.prototype when appropriate.
The Original Pattern
B.prototype = new A();
This was how things used to be done, before ES5's Object.create came about. (Although there were workarounds, even if they were not widely used.) The problem with this approach is that any instance-only data properties also end up on B.prototype, which is not desired. Additionally, any side effects of calling A's constructor will happen. Essentially this approach muddles two related, but different concepts: object instantiation, and object construction.
The Non-Standard Pattern from Your Post
for (var prop in A.prototype) {
B.prototype[prop] = A.prototype[prop];
}
This pattern has several problems:
It will copy properties from everywhere in A's prototype chain, all the way down to Object, directly into B.prototype. This defeats much of the purpose of prototypal inheritance, wherein you should be delegating up the prototype chain, instead of squashing it into one single level.
It only gets enumerable properties from A.prototype and its prototype chain, since for ... in skips non-enumerable properties.
It messes up any getters or setters defined on A.prototype (or its prototype chain), simply copying over their value instead of the getter/setter functions.
It will look effin' weird to anyone trying to read your code.
Here is another method using the factory pattern, no prototypes:
/* parent */
function Animal(name, legs)
{
/* members and methods declared within a new object */
var obj =
{
name: name,
legs: legs,
description: function ()
{
return this.name + " is an animal";
},
printNumLegs: function ()
{
return this.name + " has " + this.legs + " legs";
}
}
return obj;
}
/* subclass */
function Cat()
{
/* apply parent arguments in the context of the current object */
var obj = Animal.apply(this, arguments);
/* public member */
obj.furColor = "black";
/* private member */
var sleeping = false;
/* private method */
function printSleepingState()
{
/* can access public member ('name') without it being passed as constructor argument */
return obj.name + " is " + (sleeping ? "sleeping" : "not sleeping");
}
/* declare a new method */
obj.printFurColor = function ()
{
return obj.name + " has " + obj.furColor + " fur";
}
/* overloading */
/* save parent method if needed */
var oldDescription = obj.description;
obj.description = function ()
{
return oldDescription.apply(obj) + " and " + printSleepingState();
}
return obj;
}
/* create object without new */
var kitty = Cat("Kitty", 4);
kitty.furColor = "yellow";
There is no "best" method anyway...it's all a matter of taste.
The first variant looks like a common prototypal inheritance. It has a small minus, that if function A takes some required arguments, you should pass them when setting a prototype for function B. It also creates an instance of a parent object for a prototype. If you don't need such a behavior the second variant looks useful.
By the way:
Take a look at The third variant to make prototypal inheritance. This is also very useful sometimes.
EDIT: As far as I understood, the third variant is an old-fashioned variant of Domenic's solution (for old browsers that have no Object.create function).
I realize this answer is late, but I thought I would add comments for future readers.
I would like to add that there are other options than the those described above.
An alternative to inheritance is mix-ins. Visit http://javascriptweblog.wordpress.com/2011/05/31/a-fresh-look-at-javascript-mixins/
There are some similarities between mix-ins, and approach #2, but they are different.
In many situations, Mixins can be much more flexible than the inheritance techniques described above because they allow one object to be mixed (take on behaviour) from several mix-ins.
Although mix-ins add behaviour, they typically do not add state to your object.
Related
AFAIK, JS provides inheriatnce by means of assigning a prototype chain to a newly created object. So, the code below seems to be the correct way to me:
function Animal(name){
this.name = name;
}
Animal.prototype.getName = function(){return this.name;};
function Cat(){
Animal.apply(this, arguments);
}
Cat.prototype = Object.create(Animal.prototype);
Cat.prototype.constructor = Cat;
Cat.prototype.sayHi = function(){return 'Hi, my name is '+this.name+', and I am a "'+this.constructor.name+'" instance';};
Is this actually correct? And, I've read, that mutating object's prototype is a slow discouraged operation, that affects all the later calls to it. But here we've just mutated Animal.prototype and Cat.prototype. So, is that bad? If it is how do we deal with it? Or I've misunderstood something about that prototype mutating warning? If so, what does it actually mean?
Is this actually correct?
In that it doesn't contain anything that might be considered poor practice, yes. Whether it's correct in terms of the outcome being what you expected can't be determined.
And, I've read, that mutating object's prototype is a slow discouraged operation,
I have no idea what that means. However, it's not considered good practice to modify objects you don't own, so don't go messing with built–in or host objects (there are many articles on why not, e.g. What's wrong with extending the DOM and Extending builtin natives. Evil or not?).
that affects all the later calls to it.
Modifying a prototype may affect all objects that have it as their [[Prototype]], that's the point of prototype inheritance.
But here we've just mutated Animal.prototype and Cat.prototype. So, is that bad?
Of itself, no. If it achieves the outcome you require, then fine. You're defining the constructor, prototype properties and inheritance scheme, so it's up to you. There might be more efficient or more easily maintained schemes, but that's another topic.
Comment
Complex inheritance schemes are rarely useful in javascript, there just isn't much call for it. Most built–in objects have only one or two levels of inheritance (e.g. function instances inherit from Function.prototype and Object.prototype). Host objects (e.g. DOM elements) may have longer chains, but that is for convenience and not really necessary (at least one very popular browser didn't implement prototype inheritance for host objects until recently).
You're on the right track. You don't want to mutate Animal's prototype because that breaks the concept of inheritance. As was mentioned in the comments, using Object.create() is the correct way to inherit properties and methods from one object to another. A simple example of prototypical inheritance, using your example, is achieved this way:
function Animal(name) {
this.name = name;
}
Animal.prototype = {
getName: function() {
return this.name;
}
};
function Cat(name, color) {
Animal.call(this, name);
this.color = color;
}
Cat.prototype = Object.create(Animal.prototype);
Cat.prototype.constructor = Cat;
Cat.prototype.getColor = function() {
return this.color;
};
var animal = new Animal('Bob');
var cat = new Cat('Tabby', 'black');
console.log(cat.getName());
console.log(cat.getColor());
console.log(animal.getName());
console.log(animal.getColor()); // throws an error
Hi inheritance in JavaScript is rather complex and you will have to have a good understanding of the prototype object. Ill suggest you use the inheritance pattern of for instance TypeScript. You can give it a try on the Playground
Take a look at this:
var extends = this.extends || function (class, parent) {
for (var property in parent) {
if (parent.hasOwnProperty(property)) {
class[property] = parent[property];
}
}
function newClass() {
this.constructor = class;
}
newClass.prototype = parent.prototype;
class.prototype = new newClass();
};
var Animal = (function () {
function Animal(name) {
this.name = name;
}
return Animal;
})();
var Cat = (function (_super) {
extends(Cat, _super);
function Cat(name) {
_super.call(this, name);
}
Cat.prototype.sayHi = function () {
return "Hello my name is:" + this.name;
};
return Cat;
})(Animal);
You seem to be mixing the prototype property of functions with the internal [[proto]] property of all objects (including functions). They are two distinct things.
Mutating the internal [[proto]] property of an object is discouraged. This can be done either via setPrototypeOf or via the __proto__ accessor, which is inherited from Object.prototype:
var a = {}; // `a` inherits directly from `Object.prototype`
var b = {}; // `b` inherits directly from `Object.prototype`
a.__proto__ = b; // `a` now inherits directly from `b`
// or
Object.setPrototypeOf(a, b); // `a` now inherits directly from `b`
This is what is discouraged, mutating the internal [[proto]] property of an object after it has been created. However, it should be noted that while the object is being created it's alright to assign any object as its internal [[proto]] property.
For example, many JavaScript programmers wish to create functions which inherit from some object other than Function.prototype. This is currently only possible by mutating the internal [[proto]] property of a function after it has been created. However, in ES6 you will be able to assign the internal [[proto]] property of an object when it is created (thus avoiding the problem of mutating the internal [[proto]] property of the object).
For example, consider this bad code:
var callbackFunctionPrototype = {
describe: function () {
alert("This is a callback.");
}
};
var callback = function () {
alert("Hello World!");
};
callback.__proto__ = callbackFunctionPrototype; // mutating [[proto]]
callback.describe();
It can be rewritten in ES6 as follows:
var callbackFunctionPrototype = {
describe: function () {
alert("This is a callback.");
}
};
// assigning [[proto]] at the time of creation, no mutation
var callback = callbackFunctionPrototype <| function () {
alert("Hello World!");
};
callback.describe();
So, mutating the internal [[proto]] property of an object (using either setPrototypeOf or the __proto__ accessor) is bad. However, modifying the prototype property of a function is fine.
The prototype property of a function (let's call the function F) only affects the objects created by new F. For example:
var myPrototype = {
describe: function () {
alert("My own prototype.");
}
};
function F() {}
var a = new F; // inherits from the default `F.prototype`
alert(a.constructor === F); // true - inherited from `F.prototype`
F.prototype = myPrototype; // not mutating the `[[proto]]` of any object
var b = new F; // inherits from the new `F.prototype` (i.e. `myPrototype`)
b.describe();
To know more about inheritance in JavaScript read the answer to the following question:
JavaScript inheritance and the constructor property
Hope that helps.
My JavaScript code:
console.clear();
function BaseClass(nname) {
var name = nname;
this.bc_PublicProperty = "DefaultValue_BaseClass";
this.bc_getName = function GetName() {
return name;
};
this.bc_setName = function SetName(nname) {
name = nname;
};
}
function SubClass(nname) {
BaseClass.call(this, nname);
this.sc_PublicProperty = "DefaultValue_SubClass";
this.sc_getName = function GetName() {
return name;
};
this.sc_setName = function SetName(nname) {
name = nname;
};
}
SubClass.prototype = Object.create(BaseClass.prototype);
SubClass.prototype.constructor = SubClass;
var bc = new BaseClass("Anton");
var sc = new SubClass("Bernd");
console.log("hasOwnProperty check on subclass object 'sc' returns true for Method 'bc_getName'");
for (var pro in sc) {
console.log("Is " + pro + " own property of subclass: --> " + Object.hasOwnProperty.call(sc, pro));
}
I have two objects (BaseClass and SubClass). One inherits from the other using the constructor pattern, as explained on MDN.
Now, when I iterate over all properties of the subclass object, they all return true for hasOwnProperty, even for the parent methods/properties, except constructor.
Does it mean, that it breaks when using the constructor pattern?
When I put public properties and methods in the constructor function, whether in BaseClass or SubClass, they will always be "marked" as own properties/methods. When I instead attach them to the respective prototype, the hasOwnProperty will output "false" for them.
Whether you put the public methods/properties to the prototype or to the constructor function itself, they will all be available for use in the subClass (--> SubClass2, --> SubClass3).
The only thing, that I can think of right now, why you should attach them to the prototype object, is because of efficiency reasons, as explained here, "Defining class methods"-section. In order not to add closures for every constructed instance.
Value Types should be declared on the prototype, but not for instance variables whose initial values are dependent on arguments to the constructor, or some other state at time of construction.
You can override both properties/functions irrespective of their place of declaration.
Also setting up getters and setters on the prototype, for instance to set or get a private variable, makes no sense, as the private variable has to be public, in order to be accessible by the getters and setters attached to the prototype.
Therefore it makes no sense to use getters and setters. You can access the public variable directly.
I have to adjust my question a bit now:
When do I need hasOwnProperty, if actually public props/functions should be declared on the prototype, which in turn will all output Object.hasOwnProperty(obj,"prop/func") --> false. Give me a use case, when it makes sense, to use hasOwnProperty.
console.clear();
var l = function(v) {
console.log(v);
};
function BaseClass(nname) {
this.bc_nameProp = nname;
this.bc_ownFunc = function() {
l("bc_ownFunc of BaseClass called");
};
this.bc_getName = function GetName() {
return this.bc_nameProp;
};
}
BaseClass.prototype.bc_getName = function GetName() {
return this.bc_nameProp;
};
BaseClass.prototype.bc_PublicProperty = "DefaultValue_BaseClass";
BaseClass.prototype.bc_setName = function SetName(nname) {
bc_nameProp = nname;
};
function SubClass(nname) {
BaseClass.call(this, nname);
this.sc_setName = function SetName(nname) {
bc_nameProp = nname;
};
this.bc_getName = function GetName() {
return "xyz";
};
}
SubClass.prototype = Object.create(BaseClass.prototype);
SubClass.prototype.constructor = SubClass;
SubClass.prototype.sc_getName = function GetName() {
return this.bc_nameProp;
};
SubClass.prototype.sc_PublicProperty = "DefaultValue_SubClass";
var bc = new BaseClass("Anton");
var sc = new SubClass("Bernd");
l("----- iterating over BaseClass properties ------");
l("");
for (var pro in bc) {
l("Is " + pro + " own property of BaseClass: --> " + Object.hasOwnProperty.call(bc, pro));
}
l("");
l("----- iterating over SubClass properties ------");
l("");
for (var p in sc) {
l("Is " + p + " own property of subclass: --> " + Object.hasOwnProperty.call(sc, p));
}
l(bc.bc_getName());
l(sc.bc_getName());
l(sc.sc_getName());
Solution
When I asked this question, I was of the opinion, that when using classical inheritance in JavaScript, I can differentiate which properties/functions of my subclass directly belong to it, using hasOwnProperty. Which is not possible, as all the properties/functions of the parent prototype are copied to the prototype of the SubClass:
SubClass.prototype = Object.create(BaseClass.prototype);
All properties/functions attached to prototypes return "false", when using hasOwnProperty.
And if you have public properties/functions declared in the constructor functions of BaseClass and SubClass, all these properties return "true", when calling hasOwnProperty for these properties on the subclass.
These are copied to the SubClass using this statement:
BaseClass.call(this, nname);
So using hasOwnProperty while iterating over all properties of an obj of type SubClass, will output false for all properties/functions declared on prototype level and true for all properties/functions declared on constructor function level.
Now, I understand why using hasOwnProperty in this use case makes no sense.
Check that you're calling BaseClass.call(this) on SubClass's constructor, meaning that you're adding BaseClass properties and functions to the SubClass instance, because this is an instance of SubClass.
This is why hasOwnProperty returns true for all properties.
Wrong prototypes...
At the end of the day, you're not taking advantage of prototypes in JavaScript.
Functions that must be part of any instance of some prototype should be defined in the prototype itself.
var A = function() {};
A.prototype = {
doStuff: function() {}
};
Actually, the only benefit of defining functions during construction-time is that you ensure that an object will always define some functions/properties, but you're ensuring this once the object has been already created.
For me, there's a very small difference between the following ways of defining properties:
var A = function() {};
var instance = new A();
instance.text = "Hello, World!";
// or...
var A = function() {
this.text = "Hello, World!";
};
var instance = new A();
The first code sample defines a text property after the constructor has been called while the second one does it inside the constructor, but in both cases either this or instance are references to the same object (i.e. the instance of A).
With prototypes you ensure that all objects created from some constructor function will share the same members, and these members will be inherited and consumed using prototype chain.
About the OP's update...
The OP said a lot of things, but summarizing said:
[...] I have to adjust my question a bit now: When do I need
hasOwnProperty, if actually public props/functions should be declared
on the prototype, which in turn will all output
Object.hasOwnProperty(obj,"prop/func") --> false. Give me a use case,
when it makes sense, to use hasOwnProperty.
You're going in the wrong way... Why asking yourself when you need hasOwnProperty? Ask yourself when you need simple objects with less reusability or when you need actual reusability. hasOwnProperty has nothing to do with this issue.
When you use a literal object (i.e. ones declared as is with {} syntax)? When you need dictionaries, argument maps, value objects... Here you like hasOwnProperty because usually your code receiving arguments will look like this:
function X(uri, options) {
if(typeof options != "undefined") {
// For example, we set a default value if options has no
// mimeType property...
options.mimeType = options.hasOwnProperty("mimeType") ? options.mimeType : "application/json";
}
}
When do you use complex objects using prototypes? When you define behavior and you need to reuse it across your application or even multiple applications, and also you need to add more behavior on top of generic requirements (hello inheritance).
About why using hasOwnProperty...
The OP said:
But why would you use "hasOwnProperty" here, if you want to check the
existence of an property? Shouldn't it be: options.mimeType =
options.mimeType || "application/json";
There's a lot of code on the Internet doing the `options.mimeType =
options.mimeType || "application/json", right, because in JavaScript undefinedevaluates tofalse(ifoptionsdoesn't own amimeTypeproperty returnsundefined`).
In my humble opinion, I would use hasOwnProperty because it returns a boolean either if it exists or it exists and it has undefined as the value.
For example, options could be defined as { mimeType: undefined } and sometimes you want to know if the property exists even if it has undefined as value. The undefined as false treats the case of if it's undefined, either if it exists or not, do X, and hasOwnProperty is I want to be sure it has the property or not.
So why would I use options.hasOwnProperty over other approaches?. Easy: because, since language gives a tool to verify if a property exists in some object, why do I need a trick? object.hasOwnProperty returns true or false, and I'm sure the property exists or not, even if the property has undefined value.
With options.hasOwnProperty("mimeType") I can throw an Error if it exists and it has an undefined value. Why do I prefer this? Because I like the fail-fast concept: if you gave me the property with undefined value I tend to think that there's some bug in your code. Define it or not, my friend!
I'm going to assume by "constructor" pattern, you mean assigning this.fn = function (){}; and this.val = true; in the constructor function.
The this in the context of the BaseClass.call is changed to be the sub class, so all assignments within that are made on the sub class itself. Strictly speaking this isn't actually doing any sort of inheritance at all. Let me explain a bit in the code.
SubClass.prototype = Object.create(BaseClass.prototype);
In this line, you would be inheriting the prototype of the BaseClass on the sub class, which would ordinarily mean inheritance. However, the prototype for the BaseClass is the exact same prototype of the Function object, which the SubClass was already inheriting from. The this.___ assignments do not add to the prototype of an object, only to an instance of that object. To add to the prototype, you would need to do something along the lines of BaseClass.prototype.___ = 'foo'; However, you don't want to do that in the constructor, as that assignment is then happening every time you create a new object.
Also, in your code, calling SubClass.getName will throw an error. name is not defined in that context, only in the BaseClass context.
I'm just getting into JavaScript and I'm trying to wrap my head around prototypal inheritance. It appears that there's multiple ways to achieve the same effect, so I wanted to see if there is any best practices or reasons to do things one way over the other. Here's what I'm talking about:
// Method 1
function Rabbit() {
this.name = "Hoppy";
this.hop = function() {
console.log("I am hopping!");
}
}
// Method 2
function Rabbit() {}
Rabbit.prototype = {
name: "Hoppy",
hop: function() {
console.log("I am hopping!");
}
}
// Method 3
function Rabbit() {
this.name = "Hoppy";
}
Rabbit.prototype.hop = function() {
console.log("I am hopping!");
}
// Testing code (each method tested with others commented out)
var rabbit = new Rabbit();
console.log("rabbit.name = " + rabbit.name);
rabbit.hop();
All of these appear to have the same effect individually (unless I'm missing something). So is one method preferred over the other? How do you do it?
When you put a method on the prototype, every instance object shares the same reference to the method. If you have 10 instances, there is 1 copy of the method.
When you do what you did in example 1, every instance object has its own version of the same method, so if you create 10 of your objects, there are 10 copies of the code running around.
Using the prototype works because javascript has machinery for associated a function execution with a instance, i.e. it sets the this property for the execution of the function.
So using the prototype is highly preferred since it uses less space (unless of course, that is what you want).
In method 2, you are setting the prototype by setting it equal to an object literal. Note that here you are setting a property, which I think you don't intend to do, since all instances will get the same property.
In Method 3, you are building the prototype one assignment at a time.
I prefer method 3 for all things. i.e. In my constructor I set my property values
myObj = function(p1){
this.p1; // every instance will probably have its own value anyway.
}
myObj.prototype.method1 = function(){..} // all instances share the same method, but when invoked **this** has the right scope.
Let's look at your examples one at a time. First:
function Rabbit() {
this.name = "Hoppy";
this.hop = function() { //Every instance gets a copy of this method...
console.log("I am hopping!");
}
}
var rabbit = new Rabbit();
The above code will work, as you have said in your question. It will create a new instance of the Rabbit class. Every time you create an instance, a copy of the hop method will be stored in memory for that instance.
The second example looked like this:
function Rabbit() {}
Rabbit.prototype = {
name: "Hoppy",
hop: function() { //Now every instance shares this method :)
console.log("I am hopping!");
}
}
var rabbit = new Rabbit();
This time, every instance of Rabbit will share a copy of the hop method. That's much better as it uses less memory. However, every Rabbit will have the same name (assuming you don't shadow the name property in the constructor). This is because the method is inherited from the prototype. In JavaScript, when you try to access a property of an object, that property will first be searched for on the object itself. If it's not found there, we look at the prototype (and so on, up the prototype chain until we reach an object whose prototype property is null).
Your third example is pretty much the way I would do it. Methods shared between instances should be declared on the prototype. Properties like name, which you may well want to set in the constructor, can be declared on a per-instance basis:
function Rabbit(rabbitName) {
this.name = rabbitName;
}
Rabbit.prototype.hop = function() {
console.log("Hopping!");
}
This is an important issue that is often misunderstood. It depends what you're trying to do. Generally speaking, hvgotcode's answer is right on. Any object that will be instantiated frequently should attach methods and properties to the prototype.
But there are advantages to the others in very specific situations. Read this, including the comments: http://net.tutsplus.com/tutorials/javascript-ajax/stop-nesting-functions-but-not-all-of-them/
There are occasions when method 1 above helps, enabling you to have "private" readable/writable properties and methods. While this often isn't worth the sacrifice in heavily instantiated objects, for objects instantiated only once or a few times, or without many internal assignments, or if you're in a dev team environment with lots of different skill levels and sensibilities, it can be helpful.
Some devs incorporate another good strategy that attempts to bridge some of the shortcomings of the others. That is:
var Obj = function() {
var private_read_only = 'value';
return {
method1: function() {},
method2: function() {}
};
};
// option 4
var Rabbit {
constructor: function () {
this.name = "Hoppy";
return this;
},
hop: function() {
console.log("I am hopping!");
}
};
var rabbit = Object.create(Rabbit).constructor();
console.log("rabbit.name = " + rabbit.name);
rabbit.hop();
When doing prototypical OO using new and constructor functions is completely optional.
As has already been noted, if you can share something through the prototype do so. Prototypes are more efficient memory wise and they are cheaper in terms of instantiation time.
However a perfectly valid alternative would be
function Rabbit() {
// for some value of extend https://gist.github.com/1441105
var r = extend({}, Rabbit);
r.name = "Hoppy";
return r;
}
Here your extending "instances" with the properties of the "prototype". The only advantage real prototypical OO has is that it's a live link, meaning that changes to the prototype reflect to all instances.
Do some performance testing (declare around 1 milion rabbit variables) . First method will be the most time and memory consuming.
What are the basic ways of defining reusable objects in Javascript? I say reusable to exclude singleton techniques, such as declaring a variable with object literal notation directly. I saw somewhere that Crockford defines four such ways in his book(s) but I would rather not have to buy a book for this short bit of information.
Here are the ways I'm familiar with:
Using this, and constructing with new (I think this is called classical?)
function Foo() {
var private = 3;
this.add = function(bar) { return private + bar; }
}
var myFoo = new Foo();
Using prototypes, which is similar
function Foo() {
var private = 3;
}
Foo.prototype.add = function(bar) { /* can't access private, correct? */ }
Returning a literal, not using this or new
function Foo() {
var private = 3;
var add = function(bar) { return private + bar; }
return {
add: add
};
}
var myFoo = Foo();
I can think of relatively minor variations on these that probably don't matter in any significant way. What styles am I missing? More importantly, what are the pros and cons of each? Is there a recommended one to stick to, or is it a matter of preference and a holy war?
Use the prototype. Returning specific objects from constructors makes them non-constructors, and assigning methods to this makes inheritance less convenient.
Returning an object literal
Pros:
If a person forgets new, they still get the object.
You can create truly private variables, since all methods of the object defined inside the constructor share its scope.
Cons:
It’s not a real constructor. Adding something to its prototype won’t change the returned objects, new or no new. new Foo() instanceof Foo would also result in false.
Using prototype
Pros:
You leave the constructor uncluttered.
This is the standard way of doing things in JavaScript, and all built-in constructors put their methods on their prototypes.
Inheritance becomes easier and more correct; you can (and should) use Object.create(ParentConstructor.prototype) instead of new ParentConstructor(), then call ParentConstructor from within Constructor. If you want to override a method, you’re able to do it on the prototype.
You can “modify” objects after they’ve already been created.
You can extend the prototypes of constructors you don’t have access to.
Cons:
It can get to be a bit too verbose, and if you want to change the function’s name, you have to change all of the functions added to the prototype, too. (Either that or define the prototype as one big object literal with a compatible property descriptor for constructor.)
They don’t share an instance-specific scope, so you can’t really have private variables.
Assigning to this.* in the constructor
Pros:
You can use closures and therefore private member variables.
Cons:
No duck typing; you can’t call a method right off of the prototype with any old object. For example, Array.prototype.slice.call(collectionLikeObject).
It's mostly a matter of preference. There's no one way to make Chicken Noodle soup, and uniform objects are the same way.
I don't use any of those 3, although they all work for their own purposes. I use a custom function called Object:deploy, and use it like this..
var a = { hey: 'hello' },
b = {}.deploy(a);
console.log(b.hey); // 'hello'
Using prototype is the best for most people because of automatic trickling.
function A() {};
A.prototype.hello = "Hey";
var a = new A();
console.log(a.hello); // 'Hey'
A.prototype.hello = "Hello";
console.log(a.hello); // 'Hello'
And contrary to popular belief, you can use private variables in prototype.
function Hello() {};
(function () {
var greeting = "Hello";
Hello.prototype.greet = function () { return greeting };
}).apply(this);
But even though that's possible, it's usually better to do..
function Hello() {};
Hello.prototype.greeting = "Hello";
Hello.prototype.greet = function () { return this.greeting };
Well the second approach (prototype) is more similar to standard classes in other languages like Python, in that you have a common "prototype" object which all instances are sharing. To compare the first and second approaches:
In approach 1, every time you call "new Foo()", you are creating a brand new object and inserting all the methods. This isn't very time or space efficient, since each Foo instance will have its own table of all the methods. You can test this by creating two Foo objects, and asking foo1.add == foo2.add (false). Approach 3 is very similar to this; I'm not sure what the semantic difference (if any) there is between approaches 1 and 3.
In approach 2, you have set up a shared prototype object containing all the methods. If you ask foo1.add == foo2.add, you get true. This is more space- and time-efficient. It also lets you add more methods to the prototype after creating instances, and they will see the new methods.
The problem with approach 2, as you say, is that you can't access the private members. But you can still add non-private members to the object itself, and access those using the prototype methods:
function Foo() {
this.private = 3;
}
Foo.prototype.add = function(bar) { return this.private + bar }
A caveat is that foo.private is visible externally.
The prototype one doesn't have a per object instance overhead only a per class overhead for the add function. This alone is the reason why I don't like the other two approaches.
Do not forget about inheritance. Some day you'll need. And for organizing inheritance the best approach is combined technic:
function Foo() {
this.array = [1, 2, 3];
this.add = function(bar) { return private + bar; }
}
Foo.prototype.add = function(bar) { }
var myFoo = new Foo();
Setting fields in constructor is useful to avoid modifying them by children objects.
Setting methods to prototype is faster then doing this every time in constructor.
i don't get why everyone is using Boy.prototype = new Human; to simulate inheritance. Look, what we want is the function's of A right? we can do that without instantiating a new A (in fact instantiating a new A does give us undesirable results, in the sense that we are actually running the instantiating function which isn't what we want)
So isn't this a better solution?
for (var prop_name in Human.prototype) {
Object.defineProperty(
Boy.prototype,
prop_name,
Object.getOwnPropertyDescriptor(Human.prototype,prop_name)
);
}
Say we are that particular and want not only the enumerable properties in Human.prototype we could still achieve it by using Object.getOwnPropertyNames and calling it on the prototype chain, which in turn is available to us through Object.getPrototypeOf.
So what exactly is the benefit of doing Boy.prototype = new Human; to simulate inheritance when we have better options available to us?
A better option is to create an intermediate to hold the prototype.
function extend(clazz, superclass) {
var intermediate = function() {};
intermediate.prototype = superclass.prototype;
clazz.prototype = new intermediate();
// Following line is optional, but useful
clazz.prototype.constructor = clazz;
}
This avoids unnecessary copying, but still means that you don't need to instantiate an object that will do work in its constructor. It also sets up the prototype chain so that you can use instanceof. It also doesn't result in superclass prototype contamination which some inheritance antipatterns can.
For completeness, your subclass should call the superclass constructor in its constructor, which you can do with Superclass.call(this);.
EDIT: Since ES5, you can replace calls to extend with
Subclass.prototype = Object.create(Superclass.prototype);
which does the same thing.
It sets up the prototype chain correctly, meaning that instanceof and isPrototypeOf() will work
It's less verbose
There are simple but ugly workarounds to prevent a constructor function from performing its usual initialization when you're just using it to create a prototype object. For example, you could either check the arguments:
function Boy(name) {
if (arguments.length == 1) {
this.name = name;
// Do other initialization
}
}
... or move the initialization into a separate method that has to be called explicitly:
function Boy(name) {}
Boy.prototype.init = function(name) {
this.name = name;
// Do other initialization
}
This has the obvious downside of requiring you to remember to call init() whenever you create a new Boy.
In ECMAScript 5 environments (current versions of most browsers, for example), a better option may be ECMAScript 5's Object.create(), which allows you to create an object which inherits directly from another object and sets up the prototype chain for you. This can be emulated (but only approximately: see Object.defineProperty in ES5?) in non-ES5 environments:
if (!Object.create) {
Object.create = function(o) {
function F() {}
F.prototype = o;
return new F();
};
}