Escolar Documentos
Profissional Documentos
Cultura Documentos
closures, prototypes,
inheritance
Stoyan Stefanov
Ajax Experience, Boston 2008
About the presenter
• Yahoo! performance
team member
• Blog: http://phpied.com
Before we start… Firebug console
Firebug console is a learning tool
Firebug console…
• Arrows ↑ and↓
• string
• boolean
• undefined
• null
What’s an object?
obj.isShiny(); // true
Object literal notation
• ,-delimited properties
• key:value pairs
• auto-incremented properties
Arrays
>>> a[0]
>>> typeof a
"object"
Arrays
• ...and methods
>>> a.sort()
>>> a.join(' < ')
"1 < 2 < 3"
Array literal notation
var array = [
"Square", "brackets",
"wrap", "the",
"comma-delimited",
"elements"
];
JSON
function boo(what) {
return what;
• or
return what;
};
Functions
function boo(what) {
return what;
• or
return what;
};
Functions are objects
>>> boo.length
>>> boo.name
"bootoo"
Functions are objects
>>> foo("doodles")
"doodles"
"moo!"
Return value
this.name = name;
this.speaks = 'fr';
this.say = function() {
};
};
An object created with constructor
>>> julien.say();
this.first = "Bruce";
};
"undefined"
"Wayne"
Constructor’s return value
this.first = "Bruce";
return "Batman";
};
"Bruce"
Naming convention
• MyConstructor
• myFunction
constructor property
true
constructor property
true
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();
'[a-z]', 'gmi');
var fn = function(a, b){ var fn = new Function(
}
Wrapper objects vs. primitive
"object"
>>> typeof 1
"number"
Primitives can act as objects
>>> "test".length
>>> (123.456).toFixed(2)
"123.46"
Prototype
prototype
"object"
Prototypes can be augmented
>>> boo.prototype.a = 1;
this.name = name;
};
Person.prototype.say = function() {
return this.name;
}
How is the prototype used?
>>> dude.name;
"dude"
>>> dude.say();
"dude"
How is the prototype used?
>>> dude.hasOwnProperty('name');
true
>>> dude.hasOwnProperty('say');
false
isPrototypeOf()
>>> Person.prototype.isPrototypeOf(dude);
true
>>> Object.prototype.isPrototypeOf(dude);
true
__proto__
>>> dude.__proto__.hasOwnProperty('say')
true
>>> dude.prototype
>>> dude.__proto__.__proto__.hasOwnProperty('toString')
true
The prototype chain
It’s alive!
"undefined"
>>> Person.prototype.numlegs = 2;
>>> dude.numlegs
2
Inheritance
Inheritance via the prototype
>>> billy.family
"Stefanov"
Inherit one more time
>>> 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
false
true
Side effect… easy to solve
>>> GrandKid.prototype.constructor =
GrandKid;
isPrototypeOf
>>> billy.isPrototypeOf(jill)
true
>>> Kid.prototype.isPrototypeOf(jill)
true
instanceof
true
true
true
Classes?
Parent.prototype.getName = function(){
return this.name;
};
function Child(){}
inherit(Child, Parent);
Option 1
function inherit(C, P) {
}
Option 2
function inherit(C, P) {
C.prototype = P.prototype;
}
Option 3
function inherit(C, P) {
var F = function(){};
F.prototype = P.prototype;
}
Option 3 + super
function inherit(C, P) {
var F = function(){};
F.prototype = P.prototype;
C.uber = P.prototype;
}
Option 3 + super + constructor reset
function inherit(C, P) {
var F = function(){};
F.prototype = P.prototype;
C.prototype.constructor = C; // reset
}
Inheritance by copying properties
• After all, inheritance is all about code reuse
function extend(parent) {
for (i in parent) {
child[i] = parent[i];
return child;
}
Inheritance by copying…
>>> child.a
1
Inheritance by copying…
function object(o) {
function F(){}
F.prototype = o;
}
Prototypal inheritance
>>> child.a;
>>> child.hasOwnProperty(a);
false
Scope
No block scope
>>> inside_block
1
Function scope
function boo() {
}
Global namespace
(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…
>>> inner()
1
Closure example #2
var inner;
function outer(){
var local = 1;
inner = function(){
return local;
};
}
example #2…
"undefined"
>>> outer()
>>> inner()
1
Closure example #3
function makePlus(arg) {
var n = function(){
return arg;
};
arg++;
return n;
}
example #3…
>>> 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
>>> 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(){
})()
Iterator
function setup(x) {
var i = 0;
return function(){
return x[i++];
};
}
Iterator usage
>>> next()
'a'
>>> next()
'b'
Loop through DOM elements - wrong
document.getElementById('btn'+i).onclick =
function(){
alert(i);
};
}
Loop through DOM elements - correct
document.getElementById('btn'+i).onclick =
(function(i){
return function(){alert(i);};
})(i)
}
Wrapping up…
if (whatever == undefined) {
}
>>> obj instanceof MyConstructor
• Not instanceof()
• prototype property
Prototype
• Returns an object
Class
• Prototypal
• Classical
Stoyan Stefanov
http://www.phpied.com