Prototypes in Javascript
Prototypal Inheritance and the Chain Gang
First class functions?
- Create new functions from preexisting functions at run-time
- Store functions in collections
- Use functions as arguments to other functions
- Use functions as return values of other functions
A language supports first class functions if:
What is an Object
//this is an object
var myObject = {};
//you can add properties(values) and methods(functions) to an object
myObject.name = 'Sam Object';
myObject.whatIsMyName = function() {
return this.name;
}
//That's it.
What's wrong with this Object?
I can't reuse it or make multiple copies of it.
(without call, apply, bind)
KWOW THESE WORDS
- CLASS/FUNCTION
- OBJECT
- INSTANCE
...AND WHY THEY ARE DIFFERENT
ALSO IMPORTANT
- INHERITANCE
- CONSTRUCTOR
- CONTEXT
http://stackoverflow.com/questions/17525450/object-vs-class-vs-function
What Are Prototypes
- Prototypes are JUST Functions
- new keyword is what depicts the difference between JUST a function and a constructor
- Prototypes are SINGULAR
- Prototype functions can have different CONTEXT but are same instance of function. This has a small memory footprint.
- EVERY object has a prototype
- Every object inherits from Object..and it's prototype
- This is called prototypical inheritance
- Prototypes in JavaScript are mostly used to emulate classic OOP for creating complex objects and a means of inheritance.
Memory Allocation for Constructor Methods vs. Prototype Methods
Things to Know about Prototypes
- Adding a new prototype to a class will affect ALL instances of the class even if they are already created.
- Adding a new function to a class will affect ONLY that SINGLE instance of a class.
- Instance members of the same name will OVERRIDE the prototype member of the same name. This happens because of order. Prototype happens first. Constructor second.
- Prototype is a property of the constructor.
- A function's prototype is initially a null object. Only has purpose when function is invoked as constructor with new keyword.
function Song(){} //just a function
Song.prototype.play = function() {
return 'playing';
}
var song = Song(); //not invoked as a constructor...no prototype
console.log(song); // undefined
var realSong = new Song(); //invoked as constructor, returns reference to new Object(function)
console.log(realSong); // Object with play method available
console.log(realSong.prototype); //has no prototype, it was CREATED using Song's prototype
Using (or not) new with function invocation
function Song(){} //just a function, nothing done in constructor(call, this.*)
Song.prototype.play = function() {
return 'playing';
}
var song = new Song(); //invoked as constructor, returns reference to new Object(function)
console.log(song); // Object with play method available
var song2 = new Song();
console.log(song2); // Object with play method available
Song.prototype.stop = function() {
return 'stopped';
}
console.log(song, song2); //both objects now have a stop method available
Adding a function to a prototype after instance creation
Applies to all instances already created
//Constructor logic to set object properties, NOT prototype properties
function Song(){
this.play = function() {
return 'Hi-jacked';
}
}
Song.prototype.play = function() {
return 'playing';
}
var song = new Song(); //invoked as constructor
console.log(song.play()); // 'Hi-jacked'
//Instance method takes precedence since constructor gets called AFTER prototype
Constructors AND Prototypes
Constructor properties take precedence in order of execution.
Create instance of object:
- Bind prototype properties (not copy)
- Invoke constructor(copy)
//Constructor logic to set object properties, NOT prototype properties
function Song(){
this.play = function() {
throw new Error('Not implemented. Need to inherit into genre.');
}
}
Song.prototype.play = function() {
return 'playing';
}
function MetalSong(){
this.volume = 11;
}
MetalSong.prototype = Object.create(Song.prototype);
var reignInBlood = new MetalSong();
reignInBlood.play(); // 'playing'
Constructors AND Prototypes
Why would we do that??
The prototype Inheritance Chain
- All objects that inherit from another object receive all prototype properties of all objects up the prototype chain
- Adding to a prototype anywhere in the prototype chain will add property all the way up the chain.
- hasOwnProperty() will tell you if the method is defined on the current object or inherited.
- Inheritance ONLY inherits prototypes not constructor methods.
- Example: forEach example to support legacy browsers
if (!Array.prototype.forEach) {
Array.prototype.forEach = function(callback, context) {
for (var i = 0; i < this.length; i++) {
callback.call(context || null, this[i], i, this);
}
};
}
Prototypal Inheritance
Prototypes have a "chain" all the way up to Object
When a function is called on an instance of an object:
- Check for method on instance
- Check for method on current instance prototype
- Check for method on prototype of object inherited from.
- Continue up the chain until there is no further prototype
This is why ALL functions have toString(), call(), apply(), bind() methods.
//Constructor logic to set object properties, NOT prototype properties
function Song(){
this.play = function() {
throw new Error('Not implemented. Need to inherit into genre.');
}
}
Song.prototype.play = function() {
return 'playing';
}
function MetalSong(){
this.volume = 11;
}
MetalSong.prototype = Object.create(Song.prototype); //prototype is an object
function DeathMetalSong(){
this.volume = Infinity.max;
}
DeathMetalSong.prototype = Object.create(MetalSong.prototype);
var burningRottenLambs = new DeathMetalSong();
burningRottenLambs.play(); // 'playing'
Prototypal Inheritance
Prototypes have a "chain" all the way up to Object
//Constructor logic to set object properties, NOT prototype properties
function Song(){
this.play = function() {
throw new Error('Not implemented. Need to inherit into genre.');
}
}
Song.prototype.play = function() {
return 'playing';
}
function MetalSong(){}
MetalSong.prototype = Object.create(Song.prototype); //prototype is an object
function DeathMetalSong(){}
DeathMetalSong.prototype = Object.create(MetalSong.prototype);
function climbTheRopes(obj){
console.log('play() is mine: ' + obj.hasOwnProperty('play'));
console.log('Prototype is: ' + Object.getPrototypeOf(obj));
// console.log(obj.__proto__); //this is the only time you would EVER need/use proto
if(!Object.getPrototypeOf(obj)){
return;
}
climbTheRopes(Object.getPrototypeOf(obj));
}
var deadSilence = new DeathMetalSong();
climbTheRopes(deadSilence);
Things to know
- NEVER extend the Object prototype.
- Prototype definitions are not hoisted because of assignment
- __proto__ : now forget about it.
- Since a constructor is just a function you can call it like a method without new.
- Name your classes upper case as a visual signal.
- This will make the context of the object the global scope.
- Example of human proofing:
function User(first, last) {
if (!(this instanceof arguments.callee)) {
return new User(first,last);
}
this.name = first + " " + last;
}
Prototypal Inheritance and The Chain Gang
By Jason Sewell
Prototypal Inheritance and The Chain Gang
- 2,339