Upgrade to Pro — share decks privately, control downloads, hide ads and more …

JS Level Up: Prototypes

JS Level Up: Prototypes

Take a dive into JavaScript prototypes from the perspective of constructor functions. Originally given at Charlotte JS on June 18, 2015.

Vernon Kesner

June 18, 2015
Tweet

More Decks by Vernon Kesner

Other Decks in Programming

Transcript

  1. * Some like to say everything is an object Everything

    in JavaScript can act like an object
  2. Every object in JavaScript links to a prototype object console.log(

    “”.__proto__ === String.prototype ); // true! That, if you’re wondering, is pronounced “dunder proto"
  3. Constructor Functions • Constructor functions are used to create new

    objects. • Very useful when creating multiple instances of a particular object var list = new Array( 1, 2, 3 ); list.push( 4 ); // list === [ 1, 2, 3, 4 ]
  4. var list = new Array( 1, 2, 3 ); list.push(

    4 ); // list === [ 1, 2, 3, 4 ] Where did that push method come from?
  5. var list = new Array( 1, 2, 3 ); list.push(

    4 ); // list === [ 1, 2, 3, 4 ] Where did that push method come from? It’s inherited from Array.prototype!
  6. var list = new Array( 1, 2, list.push( 4 );

    // list === [ 1, 2, 3, 4 ] new Array( 1, 2, 3 )
  7. var list = new Array( 1, 2, list.push( 4 );

    // list === [ 1, 2, 3, 4 ] new Array( 1, 2, 3 ) A function is a block of code that is defined
 once but can be invoked any number of times.
  8. var list = new Array( 1, 2, list.push( 4 );

    // list === [ 1, 2, 3, 4 ] new Array( 1, 2, 3 ) Each function has a special this
 keyword, the functions invocation context
  9. var list = new Array( 1, 2, list.push( 4 );

    // list === [ 1, 2, 3, 4 ] new Array( 1, 2, 3 ) Functions used to initialize a new
 object are called Constructor Functions
  10. var list = new Array( 1, 2, list.push( 4 );

    // list === [ 1, 2, 3, 4 ] new Array( 1, 2, 3 ) All functions - because they are objects - have
 a prototype property that is a link to the prototype object
  11. So let’s look at an example function Person ( name

    ) { this.name = name; } Person.prototype.sayHi = function () { console.log( “Hi! I’m “, this.name ); } var vernon = new Person( “Vernon” ); vernon.sayHi(); // Hi! I’m Vernon
  12. Constructor Functions function Person ( name ) { this.name =

    name; } Person.prototype.sayHi = function () { console.log( “Hi! I’m “, this.name ); } var vernon = new Person( “Vernon” ); vernon.sayHi(); // Hi! I’m Vernon • Common convention is to uppercase the first character of the function name of a constructor function • The context of this within the constructor function is the newly created object • No return statement required
  13. Constructor Functions function Person ( name ) { this.name =

    name; } Person.prototype.sayHi = function () { console.log( “Hi! I’m “, this.name ); } var vernon = new Person( “Vernon” ); vernon.sayHi(); // Hi! I’m Vernon • We can add custom functionality to the prototype object of our function • This added functionality is inherited by each instance of our constructor we create • The context of methods added to the prototype object are the created instance itself
  14. Constructor Functions function Person ( name ) { this.name =

    name; } Person.prototype.sayHi = function () { console.log( “Hi! I’m “, this.name ); } var vernon = new Person( “Vernon” ); vernon.sayHi(); // Hi! I’m Vernon • A new object instance is created by invoking a constructor function with the new operator • Here, we create vernon and assign is the specified values as its properties • So, the value of vernon.name would be “Vernon” • We can now create as many “Person’s” as we want, and they will all be able to sayHi!
  15. Constructor Functions function Person ( name ) { this.name =

    name; // this === window } Person.prototype.sayHi = function () { console.log( “Hi! I’m “, this.name ); } var vernon = Person( “Vernon” ); vernon.sayHi(); // Hi! I’m Vernon • Invoking a constructor function without the new operator has unintended side effects • The context of the newly created object in the case of a missing new, is window
  16. Constructor Functions function Person ( name ) { if (

    !( this instanceof Person ) ) { return new Person( name ); } this.name = name; } Person.prototype.sayHi = function () { console.log( “Hi! I’m “, this.name ); } var vernon = new Person( “Vernon” ); vernon.sayHi(); // Hi! I’m Vernon • We can protect ourselves from these side effects by using the instanceof operator • instanceof tests whether an object has the prototype property of a constructor in its prototype chain • Here, we test the context of our constructor and return the proper invocation if needed
  17. function Person ( name ) { this.name = name; }

    Person.prototype.sayHi = function () { console.log( “Hi! I’m “, this.name ); } var vernon = new Person( “Vernon” ); vernon.sayHi(); // Hi! I’m Vernon Person.prototype.sayBye = function () { console.log( “Bye!” ); } vernon.sayBye(); // Bye!
  18. function Person ( name ) { this.name = name; }

    Person.prototype.sayHi = function () { console.log( } var vernon = new Person( vernon.sayHi(); // Hi! I’m Vernon Person console } vernon Prototypal Inheritance
  19. Prototypal Inheritance • All inheritance in JavaScript is through the

    prototype object • Object.prototype does not inherit any properties • All built-in constructors inherit from Object.prototype • Best understood by looking at an example http://bit.ly/1MNdeGU
  20. Creates a new object with the specified prototype object and

    properties Prototypal Inheritance | Object.create() var obj = {}; // Inherits from Object.prototype obj.foo = "bar"; // has an own property of foo var obj2 = Object.create( obj ); // Inherits from obj and Object.prototype obj2.bar = "baz"; // has an own property of bar var obj3 = Object.create( obj2 ); // Inherits from obj, obj2 and Object.prototype obj3.baz = "thud"; // has an own property of baz console.log( obj3.foo ); // bar console.log( obj3.bar ); // baz console.log( obj3.hasOwnProperty( “foo” ) ); // false
  21. var obj = {}; // Inherits from Object.prototype obj.foo =

    "bar"; // has an own property of foo var obj2 = Object.create obj2.bar = "baz"; // has an own property of bar var obj3 = Object.create obj3.baz = "thud"; // has an own property of baz console.log( obj3.foo ); // bar console.log( obj3.bar ); // baz console.log( obj3.hasOwnProperty( This inheritance lookup is 
 done against the prototype chain Prototypal Inheritance
  22. var obj = {}; // Inherits from Object.prototype obj.foo =

    "bar"; // has an own property of foo var obj2 = Object.create obj2.bar = "baz"; // has an own property of bar var obj3 = Object.create obj3.baz = "thud"; // has an own property of baz console.log( obj3.foo ); // bar console.log( obj3.bar ); // baz console.log( obj3.hasOwnProperty( We can leverage this to create scalable objects Prototypal Inheritance
  23. var obj = {}; // Inherits from Object.prototype obj.foo =

    "bar"; // has an own property of foo var obj2 = Object.create obj2.bar = "baz"; // has an own property of bar var obj3 = Object.create obj3.baz = "thud"; // has an own property of baz console.log( obj3.foo ); // bar console.log( obj3.bar ); // baz console.log( obj3.hasOwnProperty( Let’s look at 
 another example Prototypal Inheritance
  24. var User = function( details ) { details = details

    || {}; this.firstname = details.firstname; this.lastname = details.lastname; }; Let’s create a User constructor function
  25. var User = function( details ) { details = details

    || {}; this.firstname = details.firstname; this.lastname = details.lastname; }; User.prototype.logName = function() { console.log( this.firstname + " " + this.lastname ); }; Now, we’ll add a logName method to the prototype
  26. var User = function( details ) { details = details

    || {}; this.firstname = details.firstname; this.lastname = details.lastname; }; User.prototype.logName = function() { console.log( this.firstname + " " + this.lastname ); }; var john = new User( { firstname: "John", lastname: "Doe" } ); Finally, let’s create an instance of a User
  27. var User = function( details ) { … }; User.prototype.logName

    = function() { … }; var john = new User( { firstname: "John", lastname: "Doe" } ); var Admin = function( details ) { this.firstname = details.firstname; this.lastname = details.lastname; this.fullaccess = true; }; Now, let’s add an Admin constructor function
  28. var User = function( details ) { … }; User.prototype.logName

    = function() { … }; var john = new User( { firstname: "John", lastname: "Doe" } ); var Admin = function( details ) { this.firstname = details.firstname; this.lastname = details.lastname; this.fullaccess = true; }; Admin.prototype = new User(); Admin.prototype.constructor = Admin; We can inherit functionality from our User function
  29. var User = function( details ) { … }; User.prototype.logName

    = function() { … }; var john = new User( { firstname: "John", lastname: "Doe" } ); var Admin = function( details ) { this.firstname = details.firstname; this.lastname = details.lastname; this.fullaccess = true; }; Admin.prototype = new User(); Admin.prototype.constructor = Admin; var jane = new Admin( { firstname: "Jane", lastname: "Doe" } ); jane.logName(); // Jane Doe Our new Admin instance has access to logName
  30. Inheritance and 
 the prototype chain • ECMAScript 6 introduces

    a new set of keywords implementing “classes” in JavaScript. It’s important to note that these classes are still prototype based. • Object.create is another method of inheritance • Do not extend native prototypes unless you are back porting newer features of JavaScript to older engines http://bit.ly/1MNdeGU