Constructor vs Factory functions [duplicate] - javascript

This question already has answers here:
Use of 'prototype' vs. 'this' in JavaScript?
(15 answers)
Closed 7 years ago.
Could you explain the difference between setting methods in the constructor and through prototype object? The following code shows these two ways of setting the methods - say_hello and say_bye both work fine:
function MessageClass() {
this.say_bye = function() { alert('see ya'); };
}
MessageClass.prototype.say_hello = function() { alert('hello'); };
x = new MessageClass();
x.say_hello();
x.say_bye();

foxxtrot and annakata are both correct, but I'll throw in my 2 cents.
If you use the prototype then each instance of the "MessageClass" is really referencing the same functions. The functions exist in memory only once and are used for all instances. If you declare the methods in the constructor (or otherwise add it to a specific instance) rather than the prototype then a new function is created for each instance of MessageClass.
That being said, there is probably not any noticeable performance difference for most cases and it is unlikely that you will see a memory usage difference either. I would go with the prototype method unless you have a compelling reason to do otherwise. The only reason I can thing that you might want to declare a method in the constructor is if you need a closure. For example, if you have event handlers or you wanted to simulate private properties with getters/setters you might do:
function MessageClass() {
var self = this;
this.clickHander = function(e) { self.someoneClickedMe = true; };
var _private = 0;
this.getPrivate = function() { return _private; };
this.setPrivate = function(val) { _private = val; };
}
EDIT: Because there has been discussion about how this effects objects extended by another object with functions assigned in the constructor I'm adding a bit more detail. I might use the term "class" to simplify the discussion, but it is important to note that js does not support classes (that doesn't mean we can't do good OO development) or we would not be discussing this issue.
Most javascript libraries call the constructor on the base class and the sub class. (e.g. Prototype.js's Object.extend) This means that methods assigned in the constructor of each will be available on the resulting objects. However, if you are extending objects yourself there can be unexpected consequences.
If I take the MessageClass above and extend it:
function ErrorMessageClass() {}
ErrorMessageClass.prototype = new MessageClass();
errorMsg = new ErrorMessageClass();
Then errorMsg will have a getPrivate and setPrivate method on it, but they may not behave as you would expect. Because those functions were scoped when they were assigned (i.e. at "ErrorMessageClass.prototype = new MessageClass()" not only are the get/setPrivate methods shared, the _private variable gets shared across all instances of ErrorMessageClass as well. This essentially makes _private a static property for ErrorMessageClass. For example:
var errorA = new ErrorMessageClass();
var errorB = new ErrorMessageClass();
errorA.setPrivate('A');
console.log(errorA.getPrivate()); // prints 'A'
console.log(errorB.getPrivate()); // prints 'A'
errorB.setPrivate('B');
console.log(errorA.getPrivate()); // prints 'B'
Likewise with the clickHandler function and someoneClickedMe property:
errorA.clickHandler();
console.log(errorA.someoneClickedMe); // prints 'true'
console.log(errorB.someoneClickedMe); // prints 'true'
However, change those function definitions to use this._private:
this.getPrivate = function() { return this._private; };
this.setPrivate = function(val) { this._private = val; };
and behavior of instances of ErrorMessageClass becomes more of what you would expect:
errorA.setPrivate('A');
errorB.setPrivate('B');
console.log(errorA.getPrivate()); // prints 'A'
console.log(errorB.getPrivate()); // prints 'B'

If you bind methods by prototype JS only has to do it once and binds to an object class (which makes it elligible for OO JS extensions).
If you do the binding within the "class" function, JS has to do the work of creating and assigning for each and every instance.

The difference is when you derive a class from Message Class. Only the methods declared on the prototype will be available on child classes of Message.

Related

Object vs Class vs Function

I was wondering - what's the difference between JavaScript objects, classes and functions?
Am I right in thinking that classes and functions are types of objects?
And what distinguishes a class from a function? Or are they really the same thing, just the term for them changes according to how they are used?
function func() { alert('foo'); } // a function
func(); // call the function - alerts 'foo'
var func2 = function () { alert('hello'); } // acts the same way as 'func' surely?
func2(); // alerts 'hello'
var Class = function() { alert('bar'); }; // a class
var c = new Class(); // an istance of a class - alerts 'bar'
Sure, classes have methods and properties and can be instantiated - but then, I could do the same with any old function - or not?
As you must already be aware by now there are no classes in JavaScript. Instead functions in JavaScript may be made to behave like constructors by preceding a function call with the new keyword. This is known as the constructor pattern.
In JavaScript, everything is an object except for the primitive data types (boolean, number, and string), and undefined. On the other hand null is actually an object reference even though you may at first believe otherwise. This is the reason typeof null returns "object".
Functions in JavaScript are similar to functables in Lua (i.e. they are callable objects). Hence a function can be used in place of an object. Similarly, arrays are also objects in JavaScript. On the other hand, objects can be thought of as associative arrays.
The most important point however is that there are no classes in JavaScript because JavaScript is a prototypal object-oriented language. This means that objects in JavaScript directly inherit from other objects. Hence we don't need classes. All we need is a way to create and extend objects.
Read the following thread to learn more about prototypal inheritance in JavaScript: Benefits of prototypal inheritance over classical?
Update 2015
There are classes in JavaScript they just aren't used on older browsers:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes
It has constructors, extensions, and the like.
class Cat {
constructor(name) {
this.name = name;
}
speak() {
console.log(this.name + ' makes a noise.');
}
}
class Lion extends Cat {
speak() {
super.speak();
console.log(this.name + ' roars.');
}
}
A Class in JS:
function Animal(){
// Private property
var alive=true;
// Private method
function fight(){ //... }
// Public method which can access private variables
this.isAlive = function() { return alive; }
// Public property
this.name = "Joe";
}
// Public method
Animal.prototype.play = function() { alert("Bow wow!"); }
// .. and so on
Now when you create it's object
var obj = new Animal();
You can expect anything of this object as you would from objects in other language. Just the efforts to achieve it, was a bit different. You should also be looking at inheritance in JS.
Getting back too your question, I'll reword it as:
//Class : A representation of a set with common properties.
//object : One from the set with the same properties.
var Class = function() {alert('bar');}; // A set of function which alert 'bar'
var object = new Class(); // One of the functions who alert's 'bar'.
JavaScript does not have classes, and functions are actually objects in JavaScript (first-class citizens).
The only difference that function objects have is that they are callable.
function func() { alert('foo'); } // a function - Correct
func(); // call the function - alerts 'foo' - Correct
var func2 = function () { alert('foo'); } // same as 'func' surely? - Nope, func2 is a different object, that apparently does the same thing when called.
var Class = function() { alert('bar'); }; - It's a function with no name stored in variable Class.
var c = new Class(); - Calls function stored in Class supplying new empty object as this and returning that object. Functions called as new functionA() are expected to work as constructors and prepare a newly created object (this). In your case - constructor does nothing with the object and just alerts bar.
You also get classes in ES6 that look like this:
//class
class Cat {
//constructor
constructor() {
this.name = 'Snowball';
}
//method
meow() {
console.log('Hello, nyah! My name is ' + this.name + ' nyah!~');
}
};
There are no classes in javascript. But, there are ways to make a function to behave like a class in other languages.
A very good explanation is given here 3 way to define a class in js
Also, found a very good reference for OOP in Javascript
Object is the base type in JavaScript i.e. all the user defined data types inherits from Object in one way or another. So if you define a function or a class [note as of now JS doesn't support class construct, but its proposed in ECMAScript version 6], it will implicitly inherit from Object type.
Classes are really used for encapsulating logical functions and properties into one type / entity and you can 'new' it up using constructor syntax. So if you define a 'Customer' class, you can instantiate it multiple times and each instance / object can have different values. They can even share the values if you define class level value using prototype.
Since JS doesn't support class construct at the moment, functions can really act as individual method as well as container for other functions or types.
I hope with ECMAScript 6 we will have clear separation between these constructs similar to what we have in other languages like C#, Java etc.

Prototypal Inheritance best practices?

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.

Prototype or inline, what is the difference?

I am just learning Javascript and I was wondering, is using the prototype declaration, like this:
function TSomeObj()
{
this.name="my object";
}
TSomeObj.prototype.showname = function() {
alert(this.name);
}
Basically the same as doing it like this:
function TSomeObj()
{
this.name="my object";
this.showname = function() {
alert(this.name);
}
}
When I dump the object's properties I get the same result:
TSomeObj (inline version) =
{
'name': 'my object',
'test': function
}
TSomeObj (prototype declaration) =
{
'name': 'my object',
'test': function
}
What exactly is the benefit of using prototype declarations? Except less cluttering and more orderly sourcecode perhaps.
Update: I should perhaps have made it more clear that it was the final result i was curious about. The end result is ofcourse the same (i.e both register a new function in the object prototype) - but the way they do it is wildly different. Thank you for all replies and info!
Note: This answer is accurate but does not fully reflect the new way to create classes in JavaScript using the ES6 class Thing {} syntax. Everything here does in fact apply to ES6 classes, but might take some translation.
I initially answered the wrong question. Here is the answer to your actually-asked question. I'll leave my other notes in just in case they're helpful to someone.
Adding properties to an object in the constructor function through this.prop is different from doing so outside through Object.prototype.prop.
The most important difference is that when you add a property to the prototype of a function and instantiate a new object from it, that property is accessed in the new object by stepping up the inheritance chain rather than it being directly on the object.
var baseobj = {};
function ObjType1() {
this.prop = 2;
}
function ObjType2() {}
ObjType1.prototype = baseobj;
ObjType2.prototype = baseobj; // these now have the *same* prototype object.
ObjType1.prototype.prop = 1;
// identical to `baseobj.prop = 1` -- we're modifying the prototype
var a = new ObjType1(),
b = new ObjType2();
//a.hasOwnProperty('prop') : true
//b.hasOwnProperty('prop') : false -- it has no local property "prop"
//a: { prop = 2 }, b : { prop = 1 } -- b's "prop" comes from the inheritance chain
baseobj.prop = 3;
//b's value changed because we changed the prototype
//a: { prop = 2 }, b : { prop = 3 }
delete a.prop;
//a is now reflecting the prototype's "prop" instead of its own:
//a: { prop = 3 }, b : { prop = 3 }
A second difference is that adding properties to a prototype occurs once when that code executes, but adding properties to the object inside the constructor occurs each time a new object is created. This means using the prototype performs better and uses less memory, because no new storage is required until you set that same property on the leaf/proximate object.
Another difference is that internally-added functions have access to private variables and functions (those declared in the constructor with var, const, or let), and prototype-based or externally-added functions do not, simply because they have the wrong scope:
function Obj(initialx, initialy) {
var x = initialx,
y = initialy;
this.getX = function() {
return x;
}
var twoX = function() { // mostly identical to `function twoX() { ... }`
return x * 2;
}
this.getTwoX = function() {
return twoX();
}
}
Obj.prototype.getY = function() {
return y; // fails, even if you try `this.y`
}
Obj.prototype.twoY = function() {
return y * 2; // fails
}
Obj.prototype.getTwoY = function() {
return twoY(); // fails
}
var obj = new Obj();
// obj.y : fails, you can't access "y", it is internal
// obj.twoX() : fails, you can't access "twoX", it is internal
// obj.getTwoX() : works, it is "public" but has access to the twoX function
General notes about JavaScript objects, functions, and inheritance
All non-string and non-scalar variables in JavaScript are objects. (And some primitive types undergo boxing when a method is used on them such as true.toString() or 1.2.valueOf()). They all act somewhat like a hash/dictionary in that they have an unlimited(?) number of key/value pairs that can be assigned to them. The current list of primitives in JavaScript is: string, number, bigint, boolean, undefined, symbol, null.
Each object has an inheritance chain of "prototypes" that go all the way up to the base object. When you access a property of an object, if that property doesn't exist on the object itself, then the secret prototype of that object is checked, and if not present then that object's prototype, so on and so forth all the way up. Some browsers expose this prototype through the property __proto__. The more modern way to get the prototype of an object is Object.getPrototypeOf(obj). Regular objects don't have a prototype property because this property is for functions, to store the object that will be the prototype of any new objects created using that function as their constructor.
A JavaScript function is a special case of an object, that in addition to having the key/value pairs of an object also has parameters and a series of statements that are executed in order.
Every time a function object is invoked it is paired with another object that is accessed from within the function by the keyword this. Usually, the this object is the one that the function is a property of. For example, ''.replace() boxes the string literal to a String, then inside the replace function, this refers to that object. another example is when a function is attached to a DOM element (perhaps an onclick function on a button), then this refers to the DOM element. You can manually choose the paired this object dynamically using apply or call.
When a JavaScript function is invoked with the new keyword as in var obj = new Obj(), this causes a special thing to happen. If you don't specifically return anything, then instead of obj now containing the return value of the Obj function, it contains the this object that was paired with the function at invocation time, which will be a new empty object with the first parent in its inheritance chain set to Obj.prototype. The invoked Obj() function, while running, can modify the properties of the new object. Then that object is returned.
You don't have to worry much about the keyword constructor, just suffice it to say that obj.constructor points to the Obj function (so you can find the thing that created it), but you'll probably not need to use this for most things.
Back to your question. To understand the difference between modifying the properties of an object from within the constructor and modifying its prototype, try this:
var baseobj = {prop1: 'x'};
function TSomeObj() {
this.prop2 = 'y';
};
TSomeObj.prototype = baseobj;
var a = new TSomeObj();
//now dump the properties of `a`
a.prop1 = 'z';
baseobj.prop1 = 'w';
baseobj.prop2 = 'q';
//dump properties of `a` again
delete a.prop1;
//dump properties of `a` again
You'll see that setting a.prop1 is actually creating a new property of the proximate object, but it doesn't overwrite the base object's prop1. When you remove prop1 from a then you get the inherited prop1 that we changed. Also, even though we added prop2 after a was created, a still has that property. This is because javascript uses prototype inheritance rather than classic inheritance. When you modify the prototype of TSomeObj you also modify all its previously-instantiated objects because they are actively inheriting from it.
When you instantiate a class in any programing language, the new object takes on the properties of its "constructor" class (which we usually think of as synonymous with the object). And in most programming languages, you can't change the properties or methods of the class or the instantiated object, except by stopping your program and changing the class declaration.
Javascript, though, lets you modify the properties of objects and "classes" at run-time, and all instantiated objects of that type class are also modified unless they have their own properties that override the modification. Objects can beget objects which can beget objects, so this works in a chain all the way up to the base Object class. I put "classes" in quotes because there really isn't such a thing as a class in JavaScript (even in ES6, it's mostly syntactic sugar), except that the new keyword lets you make new objects with the inheritance chain hooked up for you, so we call them classes even though they're just the result of constructor functions being called with the new keyword.
Some other notes: functions have a Function constructor, objects have an Object constructor. The prototype of the Function constructor is (surprise, surprise) Object.
Inheriting from an object without the constructor function running
In some cases, it's useful to be able to create a new "instance of an object" without the constructor function running. You can inherit from a class without running the class's constructor function like so (almost like manually doing child.__proto__ = parent):
function inheritFrom(Class) {
function F() {};
F.prototype = Class.prototype;
return new F();
}
A better way to do this now is Object.setPrototypeOf().
The accepted answer missed the most important distinctions between prototypes and methods bound to a specific object, so I'm going to clarify
Prototype'd functions are only ever declared once. Functions attached using
this.method = function(){}
are redeclared again and again whenever you create an instance of the class. Prototypes are, thus, generally the preferred way to attach functions to a class since they use less memory since every instance of that class uses the same functions. As Erik pointed out, however, functions attached using prototypes vs attached to a specific object have a different scope, so prototypes don't have access to "private" variables defined in a function constructor.
As for what a prototype actually is, since it's an odd concept coming from traditional OO languages:
Whenever you create a new instance of a function:
var obj = new Foo();
the following logic is run (not literally this code, but something similar):
var inheritsFrom = Foo,
objectInstance = {};
objectInstance.__proto__ = inheritsFrom.prototype;
inheritsFrom.apply( objectInstance, arguments );
return objectInstance;
so:
A new object is created, {}, to represent the new instance of the function
The prototype of the function is copied to __proto__ of the new object. Note that this is a copy-by-reference, so Foo.prototype and objectInstance.__proto__ now refer to the same object and changes made in one can be seen in the other immediately.
The function is called with this new object being set as this in the function
and whenever you try to access a function or property, e.g.: obj.bar(), the following logic gets run:
if( obj.hasOwnProperty('bar') ) {
// use obj.bar
} else if( obj.__proto__ ){
var proto = obj.__proto__;
while(proto){
if( proto.hasOwnProperty('bar') ){
// use proto.bar;
}
proto = proto.__proto__;
}
}
in other words, the following are checked:
obj.bar
obj.__proto__.bar
obj.__proto__.__proto__.bar
obj.__proto__.__proto__.__proto__.bar
... etc
until __proto__ eventually equals null because you've reached the end of the prototype chain.
Many browsers actually expose __proto__ now, so you can inspect it in Firebug or the Console in Chrome/Safari. IE doesn't expose it (and may very well have a different name for the same thing internally).

JavaScript instance functions versus prototype functions [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Use of 'prototype' vs. 'this' in Javascript?
My understanding of the different kinds of JavaScript functions are as follows:
function MyObj() {
this.propOne = true;
this.publicInstanceFunc = function() {
if (propOne)
return 'public instance function';
}
function privateFunc() {
return 'private function only visible inside this constructor';
}
}
MyObj.prototype.protoFunc = function() {
if (this.propOne)
return 'prototype function shared amongst all instances of MyObj';
}
Are these correct?
In what cases should one put functions on the prototype (e.g. protoFunc) vs. in the constructor (e.g. publicInstanceFunc)?
Is using this the correct way to access properties inside prototype functions?
You can actually add another level of privilege via wrapping the whole thing in a self-executing function:
var MyObj = (function() { // scoping
var privateSharedVar = 'foo';
function privateSharedFunction() {
// has access to privateSharedVar
// may also access publicSharedVar via explicit MyObj.prototype
// can't be called via this
}
function MyObj() { // constructor
var privateInstanceVar = 'bar';
this.publicInstanceVar = 'baz';
function privateInstanceFunction() {
// has access to all vars
// can't be called via this
};
this.publicInstanceMethod = function() {
// has access to all vars
// also known as a privileged method
};
}
MyObj.prototype.publicSharedVar = 'quux';
MyObj.prototype.publicSharedMethod = function() {
// has access to shared and public vars
// canonical way for method creation:
// try to use this as much as possible
};
return MyObj;
})();
Only 'public' properties can be accessed from outside via this.
For performance reasons, you should avoid what I called 'instance' methods: For each of these, a new function object must be created for each MyObject instance, whereas there's only a single function object per 'shared' method.
Are these correct?
Err. Well, it depends what you want to do. There is no one accepted canonical model for implementing class/instance-style inheritance in JavaScript.
But this:
if (propOne)
Is probably a mistake, in that this.propOne is a property of the owner object, whereas propOne by itself is a variable that hasn't been declared (this defaults to a global variable, but is usually a wrongness).
In what cases should one put functions on the prototype (e.g. protoFunc) vs. in the constructor (e.g. publicInstanceFunc)?
A function set on the prototype is the same function shared amongst all objects. The only way it can work out what instance it belongs to is by reading ‘this’ when it is called.
A function set on ‘this’ in the constructor is a new function for every instance of the MyObj. You can possibly use this as an alternative way to bind to the owner object based on closures instead of ‘this’, which can save writing out function-binding stuff. It's a different style of object-orientation which normally you wouldn't mix with the this-based style.
1) Yes your code is right.
2) I use functions defined within the constructor function when I want to access other members defined privately inside the scope of the constructor function itself, for example, when you want to create privileged methods.
Public functions defined on the constructor function, are more computationally expensive than adding a simple function to the object prototype, but they also give you much more flexibility.
3) Yes, if the property is public you are able to access it by using the this keyword inside of a prototype extended function, since this refers to the instance of your object.
Regarding the second point, you extend the prototype so that all the already created objects get the new method.
Also, allows you to add methods to the built-in objects (like adding trim() to string).

Setting methods through prototype object or in constructor, difference? [duplicate]

This question already has answers here:
Use of 'prototype' vs. 'this' in JavaScript?
(15 answers)
Closed 7 years ago.
Could you explain the difference between setting methods in the constructor and through prototype object? The following code shows these two ways of setting the methods - say_hello and say_bye both work fine:
function MessageClass() {
this.say_bye = function() { alert('see ya'); };
}
MessageClass.prototype.say_hello = function() { alert('hello'); };
x = new MessageClass();
x.say_hello();
x.say_bye();
foxxtrot and annakata are both correct, but I'll throw in my 2 cents.
If you use the prototype then each instance of the "MessageClass" is really referencing the same functions. The functions exist in memory only once and are used for all instances. If you declare the methods in the constructor (or otherwise add it to a specific instance) rather than the prototype then a new function is created for each instance of MessageClass.
That being said, there is probably not any noticeable performance difference for most cases and it is unlikely that you will see a memory usage difference either. I would go with the prototype method unless you have a compelling reason to do otherwise. The only reason I can thing that you might want to declare a method in the constructor is if you need a closure. For example, if you have event handlers or you wanted to simulate private properties with getters/setters you might do:
function MessageClass() {
var self = this;
this.clickHander = function(e) { self.someoneClickedMe = true; };
var _private = 0;
this.getPrivate = function() { return _private; };
this.setPrivate = function(val) { _private = val; };
}
EDIT: Because there has been discussion about how this effects objects extended by another object with functions assigned in the constructor I'm adding a bit more detail. I might use the term "class" to simplify the discussion, but it is important to note that js does not support classes (that doesn't mean we can't do good OO development) or we would not be discussing this issue.
Most javascript libraries call the constructor on the base class and the sub class. (e.g. Prototype.js's Object.extend) This means that methods assigned in the constructor of each will be available on the resulting objects. However, if you are extending objects yourself there can be unexpected consequences.
If I take the MessageClass above and extend it:
function ErrorMessageClass() {}
ErrorMessageClass.prototype = new MessageClass();
errorMsg = new ErrorMessageClass();
Then errorMsg will have a getPrivate and setPrivate method on it, but they may not behave as you would expect. Because those functions were scoped when they were assigned (i.e. at "ErrorMessageClass.prototype = new MessageClass()" not only are the get/setPrivate methods shared, the _private variable gets shared across all instances of ErrorMessageClass as well. This essentially makes _private a static property for ErrorMessageClass. For example:
var errorA = new ErrorMessageClass();
var errorB = new ErrorMessageClass();
errorA.setPrivate('A');
console.log(errorA.getPrivate()); // prints 'A'
console.log(errorB.getPrivate()); // prints 'A'
errorB.setPrivate('B');
console.log(errorA.getPrivate()); // prints 'B'
Likewise with the clickHandler function and someoneClickedMe property:
errorA.clickHandler();
console.log(errorA.someoneClickedMe); // prints 'true'
console.log(errorB.someoneClickedMe); // prints 'true'
However, change those function definitions to use this._private:
this.getPrivate = function() { return this._private; };
this.setPrivate = function(val) { this._private = val; };
and behavior of instances of ErrorMessageClass becomes more of what you would expect:
errorA.setPrivate('A');
errorB.setPrivate('B');
console.log(errorA.getPrivate()); // prints 'A'
console.log(errorB.getPrivate()); // prints 'B'
If you bind methods by prototype JS only has to do it once and binds to an object class (which makes it elligible for OO JS extensions).
If you do the binding within the "class" function, JS has to do the work of creating and assigning for each and every instance.
The difference is when you derive a class from Message Class. Only the methods declared on the prototype will be available on child classes of Message.

Categories