0% found this document useful (0 votes)
20K views113 pages

Advanced Javascript: Closures, Prototypes, Inheritance

The document provides an overview of an "Advanced JavaScript" presentation covering topics like closures, prototypes, and inheritance. The presentation includes sections on objects, functions, constructors, the prototype chain, and inheritance implemented through extending prototypes. It discusses how closures allow functions to access variables from outer scopes even after execution leaves those scopes.
Copyright
© Attribution Non-Commercial (BY-NC)
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PPT, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
20K views113 pages

Advanced Javascript: Closures, Prototypes, Inheritance

The document provides an overview of an "Advanced JavaScript" presentation covering topics like closures, prototypes, and inheritance. The presentation includes sections on objects, functions, constructors, the prototype chain, and inheritance implemented through extending prototypes. It discusses how closures allow functions to access variables from outer scopes even after execution leaves those scopes.
Copyright
© Attribution Non-Commercial (BY-NC)
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PPT, PDF, TXT or read online on Scribd
You are on page 1/ 113

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]

>>> typeof a

"object"
Arrays

• array objects also get some cool properties...


>>> a.length
3

• ...and methods
>>> a.sort()
>>> a.join(' < ')
"1 < 2 < 3"
Array literal notation

var array = [

"Square", "brackets",

"wrap", "the",

"comma-delimited",

"elements"

];
JSON

• JavaScript Object Notation

• Uses object and array literals

• Quotes required for properties

{"num": 1, "str": "abc", "arr": [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

>>> boo.name

"bootoo"
Functions are objects

>>> var foo = boo;

>>> foo("doodles")

"doodles"

>>> foo.call(null, "moo!");

"moo!"
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 withnew, 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 "Je m'appelle " + this.name;

};

};
An object created with constructor

>>> var julien = new Person("Julien");

>>> julien.say();

"Je m'appelle Julien"


Constructor’s return value
var Person = function(){

this.first = "Bruce";

return {last: "Wayne"};

};

>>> typeof new Person().first

"undefined"

>>> new Person().last

"Wayne"
Constructor’s return value

var Person = function(){

this.first = "Bruce";

return "Batman";

};

>>> new Person().first

"Bruce"
Naming convention

• MyConstructor

• myFunction
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…
Use this Not that
var o = {}; var o = new Object();

var a = []; var a = new Array();

var re = /[a-z]/gmi; var re = new RegExp(

'[a-z]', 'gmi');
var fn = function(a, b){ var fn = new Function(

return a + b; 'a, b','return a+b');

}
Wrapper objects vs. primitive

>>> typeof new Number(1)

"object"

>>> typeof 1

"number"
Primitives can act as objects

>>> "test".length

>>> (123.456).toFixed(2)

"123.46"
Prototype
prototype

• a property of the function objects

>>> var boo = function(){};

>>> typeof boo.prototype

"object"
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;

}
How is the prototype used?

>>> var dude = new Person('dude');

>>> dude.name;

"dude"

>>> dude.say();

"dude"
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?


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
__proto__

>>> dude.__proto__.hasOwnProperty('say')

true

>>> dude.prototype

??? // Trick question

>>> dude.__proto__.__proto__.hasOwnProperty('toString')

true
The prototype chain
It’s alive!

>>> typeof dude.numlegs

"undefined"

>>> Person.prototype.numlegs = 2;

>>> dude.numlegs

2
Inheritance
Inheritance via the prototype

>>> var Dad = function(){this.family = "Stefanov";};

>>> var Kid = function(){};

>>> Kid.prototype = new Dad();


>>> var billy = new Kid();

>>> billy.family

"Stefanov"
Inherit one more time

>>> var GrandKid = function(){};

>>> GrandKid.prototype = billy;

>>> var jill = new GrandKid();

>>> jill.family

"Stefanov"
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

• classical 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;

>>> 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

"undefined"

>>> 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]();

>>> funcs[1]();

>>> 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; // usage


}; >>> getValue()
0
setValue = function(v){ >>> setValue(123)
>>> getValue()
secret = v; 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:

"string", "number", "boolean",


"undefined", "object", "function"
typeof

if (typeof whatever === "undefined") {

// 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("prop")

• Own properties vs. properties of the


prototype
obj.propertyIsEnumerable("prop")

• 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

• Classical

• … 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

You might also like