Skip to content

Instantly share code, notes, and snippets.

@AimeeKnight
Created September 16, 2018 21:46
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save AimeeKnight/106fe8970a78392f5e0176ebe7b5ef30 to your computer and use it in GitHub Desktop.
Save AimeeKnight/106fe8970a78392f5e0176ebe7b5ef30 to your computer and use it in GitHub Desktop.
JS Prototypes
// Every object in Javascript has a prototype. When a messages reaches an object, JavaScript will attempt to find a property in that object first, if it cannot find it then the message will be sent to the object’s prototype and so on. This works just like single parent inheritance in a class based language.
// The __proto__ object
// To understand prototype chains in JavaScript there is nothing as simple as the __proto__ property. Unfortunately __proto__ is not part of the standard interface of JavaScript, not at least until ES6. So you shouldn’t use it in production code. But anyway it makes explaining prototypes easy.
// let's create an alien object
var alien = {
kind: 'alien'
}
// and a person object
var person = {
kind: 'person'
}
// and an object called 'zack'
var zack = {};
// assign alien as the prototype of zack
zack.__proto__ = alien
// zack is now linked to alien
// it 'inherits' the properties of alien
console.log(zack.kind); //=> ‘alien’
// assign person as the prototype of zack
zack.__proto__ = person
// and now zack is linked to person
console.log(zack.kind); //=> ‘person’
// As you can see the __proto__ property is very straightforward to understand and use. Even if we shouldn’t use __proto__ in production code, I think that these examples give the best foundation to understand the JavaScript object model.
// You can check that one object is the prototype of another by doing:
console.log(alien.isPrototypeOf(zack))
//=> true
// Prototype lookups are dynamic
// You can add properties to the prototype of an object at any time, the prototype chain lookup will find the new property as expected.
var person = {}
var zack = {}
zack.__proto__ = person
// zack doesn't respond to kind at this point
console.log(zack.kind); //=> undefined
// let's add kind to person
person.kind = 'person'
// now zack responds to kind
// because it finds 'kind' in person
console.log(zack.kind); //=> 'person'
// New / updated properties are assigned to the object, not to the prototype
// What happens if you update a property that already exists in the prototype? Let’s see:
var person = {
kind: 'person'
}
var zack = {}
zack.__proto__ = person
zack.kind = 'zack'
console.log(zack.kind); //=> 'zack'
// zack now has a 'kind' property
console.log(person.kind); //=> 'person'
// person has not being modified
// Note that the property ‘kind’ now exists in both person and zack.
// Object.create
// As explained before __proto__ is not a well supported way of assigning prototypes to objects. So the next simplest way is using Object.create(). This is available in ES5, but old browsers / engines can be shimmed using this es5-shim.
var person = {
kind: 'person'
}
// creates a new object which prototype is person
var zack = Object.create(person);
console.log(zack.kind); // => ‘person’
// You can pass an object to Object.create to add specific properties for the new object
var zack = Object.create(person, {age: {value: 13} });
console.log(zack.age); // => ‘13’
// Object.getPrototype
// You can get the prototype of an object using Object.getPrototypeOf
// Constructor Functions
// Constructor functions are the most used way in JavaScript to construct prototype chains. The popularity of constructor functions comes from the fact that this was the only original way for constructing types. It is also an important consideration the fact that many engines are highly optimized for constructor functions.
// Unfortunately they can get confusing, they are in my opinion one of the main reasons why new comers find JavaScript puzzling, but they are a big part of the language and we need to understand them well.
// Functions as constructors
// In JavaScript you create an instance of a function like this:
function Foo(){}
var foo = new Foo();
//foo is now an instance of Foo
console.log(foo instanceof Foo ) //=> true
// In essence functions when used with the keyword new behave like factories, meaning that they create new objects. The new object they create is linked to the function by its prototype, more on this later. So in JavaScript we call this an instance of the function.
// ‘this’ is assigned implicitly
// When we use ‘new’, JavaScript injects an implicit reference to the new object being created in the form of the ‘this’ keyword. It also returns this reference implicitly at the end of the function.
// When we do this:
function Foo() {
this.kind = ‘foo’
}
var foo = new Foo();
foo.kind //=> ‘foo’
// Behind the scenes it is like doing something like this:
function Foo() {
var this = {}; // this is not valid, just for illustration
this.__proto__ = Foo.prototype;
this.kind = ‘foo’
return this;
}
// But keep in mind that the implicit ‘this’ is only assigned to a new object when using ‘new’. If you forget ‘new’ keyword then ‘this’ will be the global object. Of course forgetting new is a cause of multiple bugs, so don’t forget new.
// One convention that I like is capitalizing the first letter of a function when it is intented to be used as a function constructor, so you now straightaway to you are missing the new keyword.
// The ‘function prototype’
// Every function in JavaScript has a special property called ‘prototype’.
function Foo(){
}
Foo.prototype
// As confusing as it may sound, this ‘prototype’ property is not the real prototype (__proto__) of the function.
Foo.__proto__ === Foo.prototype //=> false
// This of course generates a lot of confusion as people use the term ‘prototype’ to refer to different things. I think that a good clarification is to always refer to the special ‘prototype’ property of functions as ‘the function prototype’, never just ‘prototype’.
// The ‘prototype’ property points to the object that will be asigned as the prototype of instances created with that function when using ‘new’. Confusing? This is easier to explain with an example:
function Person(name) {
this.name = name;
}
// the function person has a prototype property
// we can add properties to this function prototype
Person.prototype.kind = ‘person’
// when we create a new object using new
var zack = new Person(‘Zack’);
// the prototype of the new object points to person.prototype
zack.__proto__ == Person.prototype //=> true
// in the new object we have access to properties defined in Person.prototype
zack.kind //=> person
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment