Prototype vs. Not, what are benefits? - javascript

Here I made two objects; one has accessor methods created in the constructor, the other in the prototype. Why would one choose one of these over the other?
function spy1(name){
this.name = name;
var secret;
this.setSecret = function(message){
secret = message;
};
this.getSecret = function(){
return secret;
};
}
function spy2(name){
this.name = name;
this.secret;
/* (see comment) was:
var secret;
*/
}
spy2.prototype.setSecret = function(message){
this.secret = message;
/*was:
secret = message;
*/
};
spy2.prototype.getSecret = function(){
return this.secret;
/*was:
return secret;
*/
};
bond = new spy1("007");
smart = new spy2("86");
bond.setSecret("CONTROL is a joke.");
smart.setSecret("The British Secret Service is for sissies.");

The primordial differrence is that in your first example, without prototype, the getSecret and setSecret function implementation will reside on every instance of spy1.
On your second example, the functions are defined on the prototype, and all instances refer to them directly, you can test it:
var bond = new spy1("007"),
bond2 = new spy1("007");
bond.getSecret === bond2.getSecret; // <-- false since they are two functions
var smart = new spy2("86"),
smart2 = new spy2("86");
smart.getSecret === smart2.getSecret; // <-- true since is the same function
// on all instances
Also note what #T.J. commented, in your second example, using the prototype, you don't have access to the constructor function closure, and for that you are making a window.secret global variable.
If you intend to work with privileged methods, extending the prototype is not an option, all the methods that need access to the variables defined within the scope of the constructor function need to be declared inside of it...
See also: Closures.

In your first example, you're creating new functions for each instance of the object whenever you instantiate a new one. In the second, only a single copy of the function is created which is used by all the instances.
The second way can save memory. You can also use prototype chaining to implement inheritance.
Btw, your second example won't work as written. the secret variable in spy2 is local to the constructor. In the setSecret and getSecret functions in the prototype, you're accessing a single global variable.

With the second version you end up with a cleaner "constructor".

Related

necessity of prototype declaration in every method

Is is necessary to have "prototype" appended to every method of class.. or namespace is enough in example below (for full example refer link below). I understand that it is good practice but do inheritance really require the keyword "prototype" declare in every method.. what is the real necessity inheritance
if(animal === undefined) var animal = {};
animal.Mammal.prototype.haveABaby=function(){
var newBaby=new Mammal("Baby "+this.name);
this.offspring.push(newBaby);
return newBaby;
}
animal.Mammal.prototype.toString=function(){
return '[Mammal "'+this.name+'"]';
}
http://phrogz.net/JS/classes/OOPinJS2.html
prototype has nothing to see with namespace.
You define a function on prototype so that all objects created with new Mammal() will have this function (method) :
Mammal.prototype.haveABaby=function(){
...
var phoque = new Mammal();
var d = phoque.haveABaby();
In this case, all instances will share the same function. If you'd had defined the function on your instance, you'd have used more memory (not necessarily significant), and instance creation would have been longer.
If you want, you may combine it with namespaces :
animal = animal || {}; // note the simplification
animal.Mammal.prototype.haveABaby=function(){
...
var phoque = new animal.Mammal();
var d = phoque.haveABaby();
But those are two different topics.
Here's a good description of the link between prototype and inheritance.
it's needed.
If you don't have prototype then the function only gets added to the current instance. Using prototype means that when you user the new keyword, the new object will also get a copy of the function.
ie:
Mammal.toString = function() {...};
would put the toString function on Mammal - but would NOT put a toString function on every instance of Mammal. e.g. using the above non-prototype declaration:
var aDog = new Mammal();
aDog.toString() //result in undefined

Is there a performance penalty associated with methods created in the constructor versus methods created on the prototype?

I can declare methods of an object in two ways:
The first way uses the self=this idiom.
function SelfIdiomExample(name){
var self = this;
self.sayHello = function (name){
alert("Hello, "+name);
}
}
Which is useful when you need a reference to the object in a method (for example if the method will be passed as a callback). The other way is to do it by modifying the prototype:
function PrototypeModExample(){
//pass
}
PrototypeModExample.prototype.sayHello = function(name){
alert("Hello, "+name);
}
Both have the same result:
var sieg = new SelfIdiomExample();
var pmeg = new PrototypeModExample();
sieg.sayHello("Barnaby");
pmeg.sayHello("Josephine");
While I understand the use case for the self=this idiom, I am wondering:
Is there a performance penalty to using the methods created in the constructor versus methods created on the prototype?
Well this here:
var self = this;
Is not something has performance implications at all. It's wicked fast as it's simply accessing a local variable. Even from nested funcitons, this is a very fast operation in JavaScript.
However, methods created in the constructor versus methods created on the prototype has a huge performance difference.
In this example:
var PrototypeModExample = function(){
this.name = "Joe";
};
PrototypeModExample.prototype.sayHello = function(){
alert("Hello, " + this.name);
};
var a = new PrototypeModExample();
var b = new PrototypeModExample();
console.log(a.sayHello === b.sayHello); // true
Every instance of the constructor gets access to the same function objects. Which can be proved by using the === operator to compare the function objects on two instances. It will only return true when they are the same object. So globally we now have 2 instances, but they share one function object for the implementation of the sayHello method. This means that function is already setup and created when you want to make a new instance.
In other words, for all instance obj.sayHello points to the same function object, which was created before any instances existed at all.
But this on the the other hand:
function SelfIdiomExample(name){
var self = this;
this.name = "Joe";
this.sayHello = function(){
alert("Hello, " + self.name);
}
}
var a = new SelfIdiomExample();
var b = new SelfIdiomExample();
console.log(a.sayHello === b.sayHello); // false
Works differently. Now we see that the === comparison is false. That's because a new function object was created for each instance. Creating this function takes time (it needs to be parsed) and memory (this unique version of that function needs to be stored). So when creating lots of these instances, this method will be both slower and consume more memory.
In other words, for all instance obj.sayHello points to a unique function object which was created when the instance itself was created.
So usually, the prototype method is preferred. Especially in cases where a large number of instance might exist, since each instance can share function objects for it's methods.
As always, you have to test in order to answer questions like this: http://jsperf.com/this-vs-self/2.
When you test, there appears to be not much difference (less than few percent with a slight advantage to self in some cases). One advantage to self is that it can be minimized better by changing it to a one character variable name and that is apparently why some frameworks use it.
In your example, I would say that the use of self is extranous and not neccessary. Normally folks only use self when a closure is used and the value of this in some callback is no longer what you want it to be like this:
counter.prototype.incrementWithDelay(delay) {
var self = this;
setTimeout(function() {
self.counter++;
}, delay);
}
But, if you just have a normal method, there is little reason to use self.
counter.prototype.set(val) {
this.counter = val;
}

What are the differences between to create a "classic" class in javascript and JSON notation?

In Javascript there are several ways to create a class. But I have some doubts between these two ways:
function MyClass(){
this.myFun = function(){
// do stuff
}
}
and
var MyClass = {
myFun: function(){
// do stuff
}
}
The only difference is that the second way I can't to use a new operator? So the Json notation allows me to create a static class or singleton class, right?
The code you showed doesn't create classes. The notion of class is unknown to javascript, it uses prototypal inheritance. Now as to your code. The first piece of code represents a constructor function. From it, you can derive instances - javascript objects with shared properties -, using the keyword new.
function MyConstructor(name){
this.name = name || 'no name yet';
this.myFun = function(){
alert(this.name);
}
}
var instanceA = new MyConstructor('Webman')
,instanceB = new MyConstructor;
instanceA.myFun(); //=> 'Webman'
instanceB.myFun(); //=> 'no name yet'
The second piece of code creates a single javascript object. It uses an object literal notation.
var mySingleObject = {
myFun: function(){
alert('I am single');
}
};
mySingleObject.myFun(); //=> 'I am single'
The Mozilla Developer Network has a nice page, where things are explained in more detail.
Creating an object using an object literal, everything is public. Using a constructor, it is possible to have private variables, using javascripts closure mechanism:
function MyConstructor(name){
var namestring = 'the name property of this instance is: '+
(name || 'not set');
this.myFun = function(){
alert(namestring);
}
}
A few minor corrections. In JS these is only class simulation - the language lacks a formalised notion of actual classes. And your JSON notation is actually a JS object - that would be invalid JSON as you currently have it.
You do not have to use an object to simulate the singleton pattern. You can do this with constructors like so:
function Animal() {
if (Animal.instance) return Animal.instance;
Animal.instance = this;
/* constructor code here */
}
var animal_a = new Animal(); //constructor runs
var animal_b = new Animal(); //singleton instance returns
console.log(animal_a === animal_b); //true
Also, with your first approach, note it is better to put reusable, inheritable code on the prototype rather than declaring separately for each instance. This is faster, and also more sensible - the prototype is the place for this.
function Animal() {}
Animal.prototype.method = function() {}
This also avoids the problem of distinguishing between own and inherited properties, which, in your code, could not be done because you're declaring methods separately on each instance.
[EDIT - in response to the OP's question about private members]
Private members are implemented as local variables/functions, which means they are inaccessible outside the current closure.
function Animal() {
var private_var = 'foo';
function private_method = function() { alert('bar'); };
}
Public methods may (if you choose) be able to get or set them - but in order that they themselves have access to these private members, they would have to be declared inside the constructor, not separately, outside it.
function Animal() {
var private_var = 'foo';
function private_method = function() { alert('bar'); };
if (!Animal.prototype.public_method)
Animal.prototype.public_method = function() {
alert(private_var);
};
}
var dog = new Animal();
dog.public_method(); //'foo'
There are no classes in javascript, javascript is a prototypal language.
There is no way to explain this faster than watching: Crockford on JavaScript - Chapter 2: And Then There Was JavaScript for a simple CORRECT explanation by the father of json (amongst other things).
Good Luck!!

Why can`t I redefine function's prototype from within itself

I am trying to implement a way to achieve inheritance in JavaScript. First I define the base class, as follows:
function Person(name){
name = name + "!"; //I want to reuse this code for initialization
this.getName = function(){
return name;
};
this.setName = function(_name){
name = _name;
};
};
Then I define the sub class. Happens that I need a way to call the base class constructor. Ideally I would call it from within VipPerson constructor, when I still have a reference for name param. But if I do it from that point it simply does not work and if I try to access getName from base class I get an error that VipPerson has no getName method.
function VipPerson(name, vipLevel){
this.getVipLevel = function(){
return vipLevel;
};
//the line below would not work!
//VipPerson.prototype = new Person(name);
};
VipPerson.prototype = new Person(); //but this would. not ideal IMO
The drawback for me to set the prototype from outside the VipPerson is that I lose any reference to the parameter were passed.
Is there an elegant way to solve this? I would like to have this clean interface:
var foo = new Person("Foo");
console.log(foo.getName());
var bar = new VipPerson("Bar", 100);
console.log(bar.getName()); //error
console.log(bar.getVipLevel());
function VipPerson(name, vipLevel){
Person.call(this, name);
this.getVipLevel = function(){
return vipLevel;
};
};
VipPerson.prototype = Object.create(Person.prototype);
See:
https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Object/create/
However, I would avoid create closures just to make "privates" variables, unless there are specific security issues. JavaScript is a dynamic language with OOP prototype based, shouldn't be used like a class-based language with privates members.
I suggest to you to reading articles like that one: https://developer.mozilla.org/en/Introduction_to_Object-Oriented_JavaScript
It sort-of works when you set the prototype from inside the constructor, but it doesn't do what you really want. Because the setting of the prototype object is made until you're already running the constructor, the first newly created object (this) in thefirst call to the "VipPerson" constructor will not be "wired up" properly.
However, if you call the constructor again, you'll note that the prototype is there and that ".getName()" works.
Note that unless you want all your "Person" objects to share the same name, it's not going to work either way. "Person" should be set up such that "setName()" updates this.name and not a variable in the closure. There'll only be one "Person" instance for all the "VipPerson" instances — that being the instantiated prototype object.
Have you tried this approach?
function VipPerson(name, vipLevel){
this.__proto__ = new Person(name);
this.getVipLevel = function(){
return vipLevel;
};
};

Difference between a constructor and an Object

I definitely need some light on this.
What's the diference between:
var MY_APP = function(){
this.firstMethod = function(){
//something
};
this.secondMethod = function(){
//something
};
};
and
var MY_APP = {
firstKey: function(){
//something
},
secondKey: function(){
//something
}
};
besides the obvious fact that one is a Function and the other an Object, what are the differences in code flow, prototypes, patterns... whatever, and when should we use the first or the second?
I'm so spaced out in this area that i'm not sure if i'm correctly explaining the doubt, but further info can be given if you ask.
The key difference between the two is in how they are intended to be used. A constructor, as its name suggests, is designed to create and set up multiple instances of an object. An object literal on the other hand is one-off, like string and number literals, and used more often as configuration objects or global singletons (e.g. for namespacing).
There are a few subtleties about the first example to note:
When the code is executed, an anonymous function is created and assigned to MY_APP, but nothing else happens. firstMethod and secondMethod don't exist until MY_APP is explicitly called.
Depending on how MY_APP is called, the methods firstMethod and secondMethod will end up in different places:
MY_APP(): Since no context is supplied, the this defaults to window and the methods will become global.
var app1 = new MY_APP(): Due to the new keyword, a new object is created and becomes the default context. this refers to the new object, and the methods will get assigned to the new object, which subsequently gets assigned to app1. However, MY_APP.firstMethod remains undefined.
MY_APP.call(YOUR_APP): This calls my MY_APP but sets the context to be another object, YOUR_APP. The methods will get assigned to YOUR_APP, overriding any properties of YOUR_APP with the same names. This is a really flexible method that allows multiple inheritance or mixins in Javascript.
Constructors also allow another level of flexibility since functions provide closures, while object literals do not. If for example firstMethod and secondMethod rely on a common variable password that is private to the object (cannot be accessed outside the constructor), this can be achieved very simply by doing:
var MY_APP = function(){
var password = "GFHSFG";
this.firstMethod = function(){
// Do something with password
alert(password); // Woops!
};
this.secondMethod = function(){
// Do something else with password
};
};
MY_APP();
alert(password); // undefined
alert(MY_APP.password); // undefined
The first is a function, the second is an object literal. Since Functions in JS are first class objects, a function can have properties on it, just like any other object can.
Typically, if you want to create a "class" that you might be familiar with from classical inheritance languages, you would do something like
function MyClass() {...}
as is documented here http://www.crockford.com/javascript/inheritance.html
To answer the question posed in your edits, you would use them both in different situations. Object literals are used to pass configurations around. A typical usage pattern would be a method that accepts an object literal like so
something.init({
length: 10,
height: 10,
text: 'some text'
});
and so on.
You could use something similar to your first example when creating a namespace. Javascript has some interesting language features in that you can have so-called "self-invoking functions" that are of the form:
var myApp = (function(){
var firstMethod = function() {...}
...
})();
the motivations behind doing something like this are detailed here
http://sparecycles.wordpress.com/2008/06/29/advanced-javascript/
You can also investigate the differences via your favorite javascript debugging console. In firebug and chrome, I did the following:
var ol = {}; ol.prototype;
var fn = function(){}; fn.prototype;
the first line prints undefined, the second returns a prototype with a constructor of 'function'
The constructor can be reused as is, the object literal would need to be repeated or wrapped in a function to be reused.
Example of wrapping the object literal in a function:
function MY_APP() {
return {
firstKey: function(){
//something
},
secondKey: function(){
//something
}
};
}
The object created using the constructor will have it's constructor property set to the constructor function. However, as you used an anonymous function assigned to a variable instead of a named function, the constructor will still be nameless.
Other than that, there isn't really any differences. Both create anonymous functions that are assigned to the properties of the object, so the resulting objects are the same. You can compare this to assigning named functions to the properties, or using prototype functions, both having the difference that each function only exists once instead of being created over and over for each object.
There is some confusion in JavaScript regarding the difference between a function and an object.
In the first case,
var MY_APP = function() { this.v = 7; ... }
or
function MY_APP(x) { this.v = x; ... }
a function is declared, not an object. In MY_APP, this refers to the global object.
Meaning that calling the function MY_APP(7) will assign v globally to the value of 7. (and in your case the function firstMethod would be declared globally).
MY_APP(3); // The global variable v is set to 3
MY_APP(4); // The global variable v is overwritten and set to 4
To use MY_APP as an object, it needs to be instantiated, for instance
var obj1 = new MY_APP(3);
var obj2 = new MY_APP(4);
will have obj1.v to be 3, and obj2.v to be 4.
Note you can also add methods using the prototype keyword (instead of this.firstMethod...)
MY_APP.prototype.firstMethod = function () { ... }
In the second case
var MY_APP = { ... };
an object, one object, is created and its name is MY_APP. The this keywords refers to that object, MY_APP.

Categories

Resources