Advanced JavaScript: Closures, Prototypes and Inheritance ...
Upcoming SlideShare
Loading in...5
×
 

Advanced JavaScript: Closures, Prototypes and Inheritance ...

on

  • 9,034 views

 

Statistics

Views

Total Views
9,034
Views on SlideShare
9,027
Embed Views
7

Actions

Likes
16
Downloads
337
Comments
0

3 Embeds 7

http://www.slideshare.net 4
https://twimg0-a.akamaihd.net 2
http://www.scoop.it 1

Accessibility

Categories

Upload Details

Uploaded via as Microsoft PowerPoint

Usage Rights

© All Rights Reserved

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment

Advanced JavaScript: Closures, Prototypes and Inheritance ... Advanced JavaScript: Closures, Prototypes and Inheritance ... Presentation Transcript

  • Advanced JavaScript: closures, prototypes, inheritance Stoyan Stefanov Ajax Experience, Boston 2008
  • About the presenter
    • Yahoo! performance team member
    • YSlow 2.0 architect, dev
    • Book author, open-source contributor
    • Blog: http:// phpied.com
  • Before we start… Firebug console
  • Firebug console is a learning tool
  • Firebug console…
    • Inspect the contents of objects by clicking on them
    • Tab auto-complete, a.k.a cheatsheet
    • Arrows ↑ and↓
    • Fiddle with any page
  • Any page…
  • Fiddle…
  • Objects
  • JavaScript data types
    • primitive and objects
    • number
    • string
    • boolean
    • undefined
    • null
  • What’s an object?
    • a hash of key => value pairs
    • if a key ( property ) happens to be a function, we can call it a method
  • What’s an object?
    • var obj = {
    • shiny: true ,
    • isShiny: function () {
    • return this .shiny;
    • }
    • } ;
    • obj.isShiny(); // true
  • Object literal notation
    • { Wrapped in curly braces }
    • , -delimited properties
    • key : value pairs
    • var obj = {a: 1, "b c d": 2};
  • Arrays
  • Arrays
    • arrays are also objects
    • auto-incremented properties
  • Arrays
    • >>> var a = [1,3,2];
    • >>> a[0]
    • 1
    • >>> typeof a
    • "object"
  • Arrays
    • array objects also get some cool properties...
        • >>> a. length
        • 3
    • ...and methods
        • >>> a. sort ()
        • >>> a. join ( ' < ' )
        • &quot;1 < 2 < 3&quot;
  • Array literal notation
    • var array = [
    • &quot;Square&quot; , &quot;brackets&quot; ,
    • &quot;wrap&quot; , &quot;the&quot; ,
    • &quot;comma-delimited&quot; ,
    • &quot;elements&quot;
    • ];
  • JSON
    • JavaScript Object Notation
    • Uses object and array literals
    • Quotes required for properties
    • {&quot;num&quot;: 1 , &quot;str&quot;: &quot;abc&quot; , &quot;arr&quot;: [ 1 , 2 , 3 ]}
  • Functions
  • Functions
    • functions are objects
    • they have properties
    • they have methods
    • can de copied, deleted, augmented...
    • special feature: invokable
  • Functions
    • function boo(what) {
    • return what;
    • }
    • or
    • var boo = function (what) {
    • return what;
    • } ;
  • Functions
    • function boo(what) {
    • return what;
    • }
    • or
    • var boo = function bootoo (what) {
    • return what;
    • } ;
  • Functions are objects
    • >>> boo.length
    • 1
    • >>> boo.name
    • &quot;bootoo&quot;
  • Functions are objects
    • >>> var foo = boo;
    • >>> foo( &quot;doodles&quot; )
    • &quot;doodles&quot;
    • >>> foo. call ( null , &quot;moo!&quot; );
    • &quot;moo!&quot;
  • Return value
    • all functions return a value
    • if they don't explicitly, they return undefined implicitly
    • functions can return other functions
  • Constructors
  • Constructors
    • when invoked with new , functions return an object known as this
    • you have a chance of modifying this before it's returned
    • you can also return some other object
  • Constructor functions
    • var Person = function (name) {
    • this .name = name;
    • this .speaks = 'fr' ;
    • this .say = function() {
    • return &quot;Je m'appelle &quot; + this .name;
    • };
    • };
  • An object created with constructor
    • >>> var julien = new Person( &quot;Julien&quot; );
    • >>> julien.say();
    • &quot;Je m'appelle Julien&quot;
  • Constructor’s return value
    • var Person = function (){
    • this .first = &quot;Bruce&quot; ;
    • return {last: &quot;Wayne&quot; };
    • };
    • >>> typeof new Person().first
    • &quot;undefined&quot;
    • >>> new Person().last
    • &quot;Wayne&quot;
  • Constructor’s return value
    • var Person = function (){
    • this .first = &quot;Bruce&quot; ;
    • return &quot;Batman&quot; ;
    • };
    • >>> new Person().first
    • &quot;Bruce&quot;
  • Naming convention
    • M yConstructor
    • m yFunction
  • constructor property
    • >>> function Person(){};
    • >>> var jo = new Person();
    • >>> jo. constructor === Person
    • true
  • constructor property
    • >>> var o = {};
    • >>> o. constructor === Object
    • true
    • >>> [1,2]. constructor === Array
    • true
  • Built-in constructor functions
    • Object
    • Array
    • Function
    • RegExp
    • Number
    • String
    • Boolean
    • Date
    • Error, SyntaxError, ReferenceError…
  • var fn = new Function( 'a, b','return a+b'); var fn = function(a, b){ return a + b; } var re = new RegExp( '[a-z]', 'gmi'); var re = /[a-z]/gmi; var a = new Array(); var a = []; var o = new Object(); var o = {}; Not that Use this
  • Wrapper objects vs. primitive
    • >>> typeof new Number ( 1 )
    • &quot;object&quot;
    • >>> typeof 1
    • &quot;number&quot;
  • Primitives can act as objects
    • >>> &quot;test&quot; . length
    • 4
    • >>> ( 123.456 ). toFixed ( 2 )
    • &quot;123.46&quot;
  • Prototype
  • prototype
    • a property of the function objects
    • >>> var boo = function (){};
    • >>> typeof boo. prototype
    • &quot;object&quot;
  • Prototypes can be augmented
    • >>> boo. prototype .a = 1 ;
    • >>> boo. prototype .sayAh = function (){};
  • Prototypes can be overwritten
    • >>> boo. prototype = {a: 1 , b: 2 };
  • How is the prototype used?
    • when a function is invoked as a constructor
    • var Person = function (name) {
    • this .name = name;
    • };
    • Person. prototype .say = function () {
    • return this .name;
    • }
    • >>> var dude = new Person( 'dude' );
    • >>> dude.name;
    • &quot;dude&quot;
    • >>> dude.say();
    • &quot;dude&quot;
    How is the prototype used?
    • say() is a property of the prototype object
    • but it behaves as if it's a property of the dude object
    • can we tell the difference?
    How is the prototype used?
  • Own properties vs. prototype’s
    • >>> dude. hasOwnProperty ( 'name' );
    • true
    • >>> dude. hasOwnProperty ( 'say' );
    • false
  • isPrototypeOf()
    • >>> Person. prototype . isPrototypeOf (dude);
    • true
    • >>> Object . prototype . isPrototypeOf (dude);
    • true
  • __proto__
    • I, the dude , have a secret link to the prototype of the constructor that created me
    • __proto__ is not directly exposed in all browsers
    • >>> dude. __proto__ . hasOwnProperty ( 'say' )
    • true
    • >>> dude. prototype
    • ??? // Trick question
    • >>> dude. __proto__ . __proto__ . hasOwnProperty ( 'toString' )
    • true
    __proto__
  • The prototype chain
  • It’s alive!
    • >>> typeof dude.numlegs
    • &quot;undefined&quot;
    • >>> Person. prototype .numlegs = 2 ;
    • >>> dude.numlegs
    • 2
  • Inheritance
  • Inheritance via the prototype
    • >>> var Dad = function (){ this .family = &quot;Stefanov&quot; ;};
    • >>> var Kid = function (){};
    • >>> Kid. prototype = new Dad();
    • >>> var billy = new Kid();
    • >>> billy.family
    • &quot;Stefanov&quot;
  • Inherit one more time
    • >>> var GrandKid = function (){};
    • >>> GrandKid. prototype = billy;
    • >>> var jill = new GrandKid();
    • >>> jill.family
    • &quot;Stefanov&quot;
  • Inheritance…
    • >>> jill. hasOwnProperty ( 'family' )
    • false
    • >>> jill. __proto__ . hasOwnProperty ( 'family' )
    • false
    • >>> jill. __proto__ . __proto__ . hasOwnProperty ( 'family' )
    • true
  • Inheritance…
    • >>> billy.family = 'Idol' ;
    • >>> jill.family;
    • 'Idol'
    • >>> jill. __proto__ . hasOwnProperty ( 'family' );
    • true
    • >>> delete billy.family;
    • >>> jill.family;
    • 'Stefanov'
  • Side effect…
    • >>> billy. constructor === Kid
    • false
    • >>> billy. constructor === Dad
    • true
  • Side effect… easy to solve
    • reset after inheritance
    • >>> Kid. prototype . constructor = Kid;
    • >>> GrandKid. prototype . constructor = GrandKid;
  • isPrototypeOf
    • >>> billy. isPrototypeOf (jill)
    • true
    • >>> Kid. prototype . isPrototypeOf (jill)
    • true
  • instanceof
    • >>> jill instanceof GrandKid
    • true
    • >>> jill instanceof Kid
    • true
    • >>> jill instanceof Dad
    • true
  • Classes?
    • There are no classes in JavaScript
    • Objects inherit from objects
    • class ical inheritance is when we think of constructors as if they were classes
  • Classical inheritance
    • function Parent(){ this .name = 'parent' ;}
    • Parent. prototype .getName = function (){ return this .name; };
    • function Child(){}
    • inherit(Child, Parent);
  • Option 1
    • function inherit(C, P) {
    • C. prototype = new P();
    • }
  • Option 2
    • function inherit(C, P) {
    • C. prototype = P. prototype ;
    • }
  • Option 3
    • function inherit(C, P) {
    • var F = function (){};
    • F. prototype = P. prototype ;
    • C. prototype = new F();
    • }
  • Option 3 + super
    • function inherit(C, P) {
    • var F = function (){};
    • F. prototype = P. prototype ;
    • C. prototype = new F();
    • C.uber = P. prototype ;
    • }
  • Option 3 + super + constructor reset
    • function inherit(C, P) {
    • var F = function (){};
    • F. prototype = P. prototype ;
    • C. prototype = new F();
    • C.uber = P. prototype ; // super
    • C. prototype . constructor = C; // reset
    • }
  • Inheritance by copying properties
    • After all, inheritance is all about code reuse
    • function extend(parent) {
    • var i, child = {};
    • for (i in parent) {
    • child[i] = parent[i];
    • }
    • return child;
    • }
  • Inheritance by copying…
    • >>> var parent = {a: 1 };
    • >>> var child = extend(parent);
    • >>> child.a
    • 1
  • Inheritance by copying…
    • This was a shallow copy
    • you can make a deep copy using recursion
    • mixins / multiple inheritance
  • Prototypal inheritance
    • as suggested by Douglas Crockford
    • no class-like constructors involved
    • objects inherit from objects
    • via the prototype
  • Prototypal inheritance
    • function object(o) {
    • function F(){}
    • F. prototype = o;
    • return new F();
    • }
  • Prototypal inheritance
    • >>> var parent = {a: 1 };
    • >>> var child = object(parent);
    • >>> child.a;
    • 1
    • >>> child. hasOwnProperty (a);
    • false
  • Scope
  • No block scope
    • >>> if ( true ) { var inside_block = 1 ;}
    • >>> inside_block
    • 1
  • Function scope
    • function boo() {
    • var inboo = true ;
    • }
  • Global namespace
    • every variable is global unless it's in a function and is declared with var
    • global namespace should be kept clean to avoid naming collisions
    • function scope can help
  • Self-executable functions for one-off tasks
    • ( function (){
    • var a = 1 ;
    • var b = 2 ;
    • alert (a + b);
    • } )()
  • Closures
  • Photo credit: NASA
  •  
  • Closure example #1
    • function outer(){
    • var local = 1 ;
    • return function (){
    • return local;
    • };
    • }
  • example #1…
    • >>> var inner = outer()
    • >>> inner()
    • 1
  • Closure example #2
    • var inner;
    • function outer(){
    • var local = 1 ;
    • inner = function (){
    • return local;
    • };
    • }
  • example #2…
    • >>> typeof inner
    • &quot;undefined&quot;
    • >>> outer()
    • >>> inner()
    • 1
  • Closure example #3
    • function makePlus(arg) {
    • var n = function (){
    • return arg;
    • };
    • arg++;
    • return n;
    • }
  • example #3…
    • >>> var getValue = makePlus( 1234 );
    • >>> getValue()
    • 1235
  • Closure #4 – in a loop
    • function make() {
    • var i, a = [];
    • for (i = 0 ; i < 3 ; i++) {
    • a[i] = function (){
    • return i;
    • }
    • }
    • return a;
    • }
  • Closure #4 test - oops
    • >>> var funcs = make();
    • >>> funcs[ 0 ]();
    • 3
    • >>> funcs[ 1 ]();
    • 3
    • >>> funcs[ 2 ]();
    • 3
  • Closure #4 – corrected
    • function make() {
    • var i, a = [];
    • for (i = 0 ; i < 3 ; i++) {
    • a[i] = ( function (local){
    • return function (){ return local;}
    • })(i)
    • }
    • return a;
    • }
  • Getter/Setter
    • var getValue, setValue;
    • ( function () {
    • var secret = 0 ;
    • getValue = function (){
    • return secret;
    • };
    • setValue = function (v){
    • secret = v;
    • };
    • })()
    // usage >>> getValue() 0 >>> setValue( 123 ) >>> getValue() 123
  • Iterator
    • function setup(x) {
    • var i = 0 ;
    • return function (){
    • return x[i++];
    • };
    • }
  • Iterator usage
    • >>> var next = setup([ 'a' , 'b' , 'c' ]);
    • >>> next()
    • 'a'
    • >>> next()
    • 'b'
  • Loop through DOM elements - wrong
    • // all elements will alert 5
    • for (var i = 1; i < 5; i++ ){
    • document.getElementById('btn'+i).onclick =
    • function(){
    • alert(i);
    • };
    • }
  • Loop through DOM elements - correct
    • // first element alerts 1, second 2,...
    • for (var i = 1; i < 5; i++ ){
    • document.getElementById('btn'+i).onclick =
    • ( function( i ){
    • return function(){ alert(i); };
    • } )(i)
    • }
  • Wrapping up…
    • How to tell what’s going on?
    • typeof, instanceof, isPrototypeOf()…
  • >>> typeof variable
    • typeof is an operator, not a function
    • Not typeof(variable) even if it works
    • Returns a string, one of:
      • &quot;string&quot;, &quot;number&quot;, &quot;boolean&quot;,
      • &quot;undefined&quot;, &quot;object&quot;, &quot;function&quot;
  • typeof
    • if ( typeof whatever === &quot;undefined&quot;) {
    • // whatever is not defined
    • }
    • if (whatever == undefined) {
    • // hmm, not so sure
    • }
  • >>> obj instanceof MyConstructor
    • Not instanceof()
    • Returns true | false
    • true for all constructors up the chain
  • >>> obj. constructor
    • Points to the constructor function used to create this obj
  • >>> obj. isPrototypeOf (child_obj)
    • Respects the prototype chain
  • >>> obj. hasOwnProperty ( &quot;prop&quot; )
    • Own properties vs. properties of the prototype
  • obj. propertyIsEnumerable ( &quot;prop&quot; )
    • Will it show up in a for-in loop
    • Caution: enumerable properties of the prototype will return false but still show up in the for-in loop
  • Wrapping up…
    • What did we learn today?
  • Objects
    • JavaScript has a few primitive types, everything else is an object
    • Objects are hashes
    • Arrays are objects
  • Functions
    • Functions are objects, only invokable
    • call() and apply() methods
    • prototype property
  • Prototype
    • Functions have a prototype property which is an object
    • Useful with Constructor functions
  • Constructor
    • A function meant to be called with new
    • Returns an object
  • Class
    • No such thing in JavaScript
  • Inheritance
    • Prototypal
    • Class ical
    • … and approximately 101 other ways and variations
  • Scope
    • Lexical function scope
  • Closure
    • When a variable leaves its function scope
  • Thank you!
    • Stoyan Stefanov
    • http://www.phpied.com