JavaScript:

A Language of Many Contrasts

Douglas Crockford
Yahoo!
http://javascript.crockford.com/ajaxworld.ppt
The World's Most
Misunderstood
Programming Language
Sources of
Misunderstanding
•
•
•
•
•
•
•
•

The Name
Mispositioning
Design Errors
Bad Implementations
The Browser
Bad Books
Substandard Standard
JavaScript is a Functional
Language
Key Ideas
• Load and go delivery

• Loose typing
• Objects as general containers

• Prototypal inheritance
• Lambda
• Linkage through global variables
Key Ideas
• Load and go delivery

• Loose typing
• Objects as general containers

• Prototypal inheritance
• Lambda
• Linkage though global variables
It is full of warts.
For statement
• Iterate through all of the members of
an object:
for (var name in object) {
if (object.hasOwnProperty(name)) {
// within the loop,
// name is the key of current member
// object[name] is the current value
}
}
typeof
• The typeof prefix operator returns
a string identifying the type of a
value. type
typeof
object

'object'

function

'function'

array

'object'

number

'number'

string

'string'

boolean

'boolean'

null

'object'

undefined

'undefined'
with statement
• Intended as a
short-hand
• Ambiguous
• Error-prone
• Don't use it

with (o) {
foo = null;
}

 o.foo = null;
 foo = null;
It is mostly good
stuff.
Inner functions
• Functions do not all have to be
defined at the top level (or left
edge).

• Functions can be defined inside of
other functions.
Scope
• An inner function has access to
the variables and parameters of
functions that it is contained
within.
• This is known as Static Scoping or
Lexical Scoping.
Closure
• The scope that an inner function
enjoys continues even after the
parent functions have returned.

• This is called closure.
Example
function fade(id) {
var dom = document.getElementById(id),
level = 1;
function step () {
var h = level.toString(16);
dom.style.backgroundColor =
'#FFFF' + h + h;
if (level < 15) {
level += 1;
setTimeout(step, 100);
}
}
setTimeout(step, 100);
}
Inheritance
• Inheritance is object-oriented
code reuse.
• Two Schools:
• Classical
• Prototypal
Classical Inheritance
• Objects are instances of Classes.
• A Class inherits from another
Class.
Pseudoclassical
• Pseudoclassical looks sort of classical,
but is really prototypal.
• Three mechanisms:
•

Constructor functions.

•

The prototype member of functions.

•

The new operator.
Psuedoclassical
function Constructor() {
this.member = initializer;
return this; // optional
}

Constructor.prototype.firstMethod =
function (a, b) {...};
Constructor.prototype.secondMethod =
function (c) {...};
var newObject = new Constructor();
new operator
var newObject = new Constructor();
• new Constructor() returns a new

object with a link to
Constructor.prototype.

newObject

Constructor.prototype
Warning
• The new operator is required when
calling a Constructor.
• If new is omitted, the global object
is clobbered by the
constructor, and then the global
object is returned instead of a
new instance.
Syntactic Rat Poison
Constructor.
method('first_method',
function (a, b) {...}).
method('second_method',
function (c) {...});
----------------------------------Function.prototype.method =
function (name, func) {
this.prototype[name] = func;
return this;
};
Pseudoclassical Inheritance
• Classical inheritance can be simulated
by assigning an object created by one
constructor to the prototype member
of another.
function BiggerConstructor() {...};
BiggerConstructor.prototype =
new Constructor();

• This does not work exactly like the
classical model.
Example
function Gizmo(id) {
this.id = id;
}

Gizmo.prototype.toString = function () {
return "gizmo " + this.id;
};
function Gizmo(id) {

this.id = id;
}

Example

Gizmo.prototype.toString = function () {
return "gizmo " + this.id;
};

Gizmo
prototype

Object
prototype

constructor
toString

function

constructor
toString

function

new Gizmo(string)
id

string
function Gizmo(id) {

this.id = id;
}

Example

Gizmo.prototype.toString = function () {
return "gizmo " + this.id;
};

Gizmo
prototype

Object
prototype

constructor
toString

function

constructor
toString

function

new Gizmo(string)
id

string
function Gizmo(id) {

this.id = id;
}

Example

Gizmo.prototype.toString = function () {
return "gizmo " + this.id;
};

Gizmo
prototype

Object
prototype

constructor
toString

function

constructor
toString

function

new Gizmo(string)
id

string
Inheritance
• If we replace the original
prototype object with an instance
of an object of another class, then
we can inherit another class's
stuff.
Example
function Hoozit(id) {
this.id = id;
}

Hoozit.prototype = new Gizmo();
Hoozit.prototype.test = function (id) {
return this.id === id;

};
Example

function Hoozit(id) {
this.id = id;
}
Hoozit.prototype = new Gizmo();
Hoozit.prototype.test = function (id) {
return this.id === id;
};

Gizmo
prototype

Hoozit

id

constructor
toString

function

constructor

prototype

test

new Hoozit(string)

function

string
Example

function Hoozit(id) {
this.id = id;
}
Hoozit.prototype = new Gizmo();
Hoozit.prototype.test = function (id) {
return this.id === id;
};

Gizmo
prototype

Hoozit

id

constructor
toString

function

constructor

prototype

test

new Hoozit(string)

function

string
Prototypal Inheritance
• Class-free.
• Objects inherit from objects.
• An object contains a secret link to
the object it inherits from.
var newObject = object(oldObject);
newObject
__proto__

oldObject
object function
• A prototypal inheritance language
should have an operator like the
object function, which makes a
new object using an existing
object as its prototype.
object function
function object(o) {
function F() {}
F.prototype = o;
return new F();
}
object function
function object(o) {
function F() {}
F.prototype = o;
return new F();
}
newObject = object(oldObject)
F
prototype

constructor
object function
function object(o) {
function F() {}
F.prototype = o;
return new F();
}
newObject = object(oldObject)
F
prototype

constructor

oldObject
object function
function object(o) {
function F() {}
F.prototype = o;
return new F();
}
newObject = object(oldObject)
F
prototype

newObject

oldObject
object function
function object(o) {
function F() {}
F.prototype = o;
return new F();
}
newObject = object(oldObject)

newObject

oldObject
Prototypal Inheritance
var oldObject = {
firstMethod: function () {...},
secondMethod: function () {...}
};
var newObject = object(oldObject);
newObject.thirdMethod = function () {...};
var myDoppelganger = object(newObject);
myDoppelganger.firstMethod();
Prototypal Inheritance
• There is no limit to the length of
the chain (except common sense).

myDoppelganger = object(newObject);
newObject

oldObject
Augmentation
• Using the object function, we can
quickly produce new objects that
have the same state and behavior
as existing objects.
• We can then augment each of the
instances by assigning new
methods and members.
Public Method
• A Public Method is a function that
uses this to access its object.
• This binding of this to an object
happens at invocation time.
• A Public Method can be reused
with many "classes".
Public Methods
myObject.method = function (string) {
return this.member + string;
};

• We can put this function in any object
at it works.
• Public methods work extremely well
with prototypal inheritance and with
pseudoclassical inheritance.
Singletons
• There is no need to produce a
class-like constructor for an
object that will have exactly one
instance.
• Instead, simply use an object
literal.
Singletons
var singleton = {
firstMethod: function (a, b) {
...
},
secondMethod: function (c) {
...
}
};
Functions are used as
• Functions
• Methods
• Constructors
• Classes
• Modules
Module
• Variables defined in a module are
only visible in the module.
• Functions have scope.
• Variables defined in a function
only visible in the function.
• Functions can be used a module
containers.
Global variables are evil
• Functions within an application
can clobber each other.
• Cooperating applications can
clobber each other.
• Use of the global namespace must
be minimized.
Singletons
• The methods of a singleton can
enjoy access to shared private
data and private methods.
Singletons
var singleton = function () {
var privateVariable;
function privateFunction(x) {
...privateVariable...
}
return {
firstMethod: function (a, b) {
...privateVariable...
},
secondMethod: function (c) {
...privateFunction()...
}
};
}();
Applications are Singletons
var AJAX = function () {
var privateVariable;
function privateFunction(x) {
...privateVariable...
}
return {
firstMethod: function (a, b) {
...privateVariable...
},
secondMethod: function (c) {
...privateFunction()...
}
};
}();
Privacy
• All members of an object are
public.
• We want private variables and
private methods.
• Really.
Privileged Method
• A Privileged Method is a function that
has access to secret information.
• A Privileged Method has access to
private variables and private methods.
• A Privileged Method obtains its secret
information through closure.
Power Constructor
• Put the singleton module pattern
in constructor function, and we
have a power constructor
pattern.
1. Make a new object somehow.

2. Augment it.
3. Return it.
Power Constructor
function powerConstructor() {
var that = object(oldObject),
privateVariable;
function privateFunction(x) { ... }
that.firstMethod = function (a, b) {
...privateVariable...
};
that.secondMethod = function (c) {
...privateFunction()...
};
return that;
}
Power Constructor
• Public methods (from the
prototype)
var that = object(oldObject);

•
•
•
•

Private variables (var)
Private methods (inner functions)
Privileged methods
No need to use new
myObject = power_constructor();
Parasitic Inheritance
• A power constructor calls another
constructor, takes the result,
augments it, and returns it as
though it did all the work.
Psudeoclassical Inheritance
function Gizmo(id) {
this.id = id;
}
Gizmo.prototype.toString = function () {
return "gizmo " + this.id;
};
function Hoozit(id) {
this.id = id;
}
Hoozit.prototype = new Gizmo();
Hoozit.prototype.test = function (id) {
return this.id === id;
}
Parasitic Inheritance
function gizmo(id) {
return {
id: id,
toString: function () {
return "gizmo " + this.id;
}
};
}
function hoozit(id) {
var that = gizmo(id);
that.test = function (testid) {
return testid === this.id;
};
return that;
}
Secrets
function gizmo(id) {
return {
toString: function () {
return "gizmo " + id;
}
};
}
function hoozit(id) {
var that = gizmo(id);
that.test = function (testid) {
return testid === id;
};
return that;
}
Shared Secrets
function gizmo(id, secret) {
secret = secret || {};
secret.id = id;
return {
toString: function () {
return "gizmo " + secret.id;
};
};
}
function hoozit(id) {
var secret = {},
that = gizmo(id, secret);
that.test = function (testid) {
return testid === secret.id;
};
return that;
}
Super Methods
function hoozit(id) {
var secret = {},
that = gizmo(id, secret),
super_toString = that.toString;
that.test = function (testid) {
return testid === secret.id;
};
that.toString = function () {
return super_toString.apply(that, []);
};
return that;
}
Inheritance Patterns
• Prototypal Inheritance works
really well with public methods.
• Parasitic Inheritance works really
well with privileged and private
and public methods.

• Pseudoclassical Inheritance for
elderly programmers who are old
and set in their ways.
Working with the Grain
• Pseudoclassical patterns are less
effective than prototypal patterns
or parasitic patterns.

• Formal classes are not needed for
reuse or extension.
• Be shallow. Deep hierarchies are
not effective.
Performance
• Provide a good experience.
• Be respectful of our customer's
time.
• Hoare's Dictum: Premature
optimization is the root of all evil.
Efficiency
• The first priority must always be
correctness.
• Optimize when necessary.
• Consider algorithmic improvements
O (n)

v

O (n log n)

• Watch for limits.

v

O (n2)
Minification vs
Obfuscation
• Reduce the amount of source
code to reduce download time.
• Minification deletes whitespace
and comments.
• Obfuscation also changes the
names of things.
• Obfuscation can introduce bugs.
• Never use tools that cause bugs if
you can avoid it.
http://www.crockford.com/javascript/jsmin.html
Code Conventions for the
JavaScript Programming
Language
http://javascript.crockford.com/code.html
JSLint
• JSLint can help improve the
robustness and portability of your
programs.
• It enforces style rules.
• It can spot some errors that are very
difficult to find in debugging.
• It can help eliminate implied
globals.
• Commandline versions.
• In text editors and Eclipse.
JSLint
• Warning: JSLint will hurt your
feelings.
• If you follow its advice, JSLint will
make your programs better.

•http://www.JSLint.com/
JavaScript:

A Language of Many Contrasts

Douglas Crockford
Yahoo!
http://javascript.crockford.com/ajaxworld.ppt

Ajaxworld

  • 1.
    JavaScript: A Language ofMany Contrasts Douglas Crockford Yahoo! http://javascript.crockford.com/ajaxworld.ppt
  • 2.
  • 3.
    Sources of Misunderstanding • • • • • • • • The Name Mispositioning DesignErrors Bad Implementations The Browser Bad Books Substandard Standard JavaScript is a Functional Language
  • 4.
    Key Ideas • Loadand go delivery • Loose typing • Objects as general containers • Prototypal inheritance • Lambda • Linkage through global variables
  • 5.
    Key Ideas • Loadand go delivery • Loose typing • Objects as general containers • Prototypal inheritance • Lambda • Linkage though global variables
  • 6.
    It is fullof warts.
  • 7.
    For statement • Iteratethrough all of the members of an object: for (var name in object) { if (object.hasOwnProperty(name)) { // within the loop, // name is the key of current member // object[name] is the current value } }
  • 8.
    typeof • The typeofprefix operator returns a string identifying the type of a value. type typeof object 'object' function 'function' array 'object' number 'number' string 'string' boolean 'boolean' null 'object' undefined 'undefined'
  • 9.
    with statement • Intendedas a short-hand • Ambiguous • Error-prone • Don't use it with (o) { foo = null; }  o.foo = null;  foo = null;
  • 10.
    It is mostlygood stuff.
  • 11.
    Inner functions • Functionsdo not all have to be defined at the top level (or left edge). • Functions can be defined inside of other functions.
  • 12.
    Scope • An innerfunction has access to the variables and parameters of functions that it is contained within. • This is known as Static Scoping or Lexical Scoping.
  • 13.
    Closure • The scopethat an inner function enjoys continues even after the parent functions have returned. • This is called closure.
  • 14.
    Example function fade(id) { vardom = document.getElementById(id), level = 1; function step () { var h = level.toString(16); dom.style.backgroundColor = '#FFFF' + h + h; if (level < 15) { level += 1; setTimeout(step, 100); } } setTimeout(step, 100); }
  • 15.
    Inheritance • Inheritance isobject-oriented code reuse. • Two Schools: • Classical • Prototypal
  • 16.
    Classical Inheritance • Objectsare instances of Classes. • A Class inherits from another Class.
  • 17.
    Pseudoclassical • Pseudoclassical lookssort of classical, but is really prototypal. • Three mechanisms: • Constructor functions. • The prototype member of functions. • The new operator.
  • 18.
    Psuedoclassical function Constructor() { this.member= initializer; return this; // optional } Constructor.prototype.firstMethod = function (a, b) {...}; Constructor.prototype.secondMethod = function (c) {...}; var newObject = new Constructor();
  • 19.
    new operator var newObject= new Constructor(); • new Constructor() returns a new object with a link to Constructor.prototype. newObject Constructor.prototype
  • 20.
    Warning • The newoperator is required when calling a Constructor. • If new is omitted, the global object is clobbered by the constructor, and then the global object is returned instead of a new instance.
  • 21.
    Syntactic Rat Poison Constructor. method('first_method', function(a, b) {...}). method('second_method', function (c) {...}); ----------------------------------Function.prototype.method = function (name, func) { this.prototype[name] = func; return this; };
  • 22.
    Pseudoclassical Inheritance • Classicalinheritance can be simulated by assigning an object created by one constructor to the prototype member of another. function BiggerConstructor() {...}; BiggerConstructor.prototype = new Constructor(); • This does not work exactly like the classical model.
  • 23.
    Example function Gizmo(id) { this.id= id; } Gizmo.prototype.toString = function () { return "gizmo " + this.id; };
  • 24.
    function Gizmo(id) { this.id= id; } Example Gizmo.prototype.toString = function () { return "gizmo " + this.id; }; Gizmo prototype Object prototype constructor toString function constructor toString function new Gizmo(string) id string
  • 25.
    function Gizmo(id) { this.id= id; } Example Gizmo.prototype.toString = function () { return "gizmo " + this.id; }; Gizmo prototype Object prototype constructor toString function constructor toString function new Gizmo(string) id string
  • 26.
    function Gizmo(id) { this.id= id; } Example Gizmo.prototype.toString = function () { return "gizmo " + this.id; }; Gizmo prototype Object prototype constructor toString function constructor toString function new Gizmo(string) id string
  • 27.
    Inheritance • If wereplace the original prototype object with an instance of an object of another class, then we can inherit another class's stuff.
  • 28.
    Example function Hoozit(id) { this.id= id; } Hoozit.prototype = new Gizmo(); Hoozit.prototype.test = function (id) { return this.id === id; };
  • 29.
    Example function Hoozit(id) { this.id= id; } Hoozit.prototype = new Gizmo(); Hoozit.prototype.test = function (id) { return this.id === id; }; Gizmo prototype Hoozit id constructor toString function constructor prototype test new Hoozit(string) function string
  • 30.
    Example function Hoozit(id) { this.id= id; } Hoozit.prototype = new Gizmo(); Hoozit.prototype.test = function (id) { return this.id === id; }; Gizmo prototype Hoozit id constructor toString function constructor prototype test new Hoozit(string) function string
  • 31.
    Prototypal Inheritance • Class-free. •Objects inherit from objects. • An object contains a secret link to the object it inherits from. var newObject = object(oldObject); newObject __proto__ oldObject
  • 32.
    object function • Aprototypal inheritance language should have an operator like the object function, which makes a new object using an existing object as its prototype.
  • 33.
    object function function object(o){ function F() {} F.prototype = o; return new F(); }
  • 34.
    object function function object(o){ function F() {} F.prototype = o; return new F(); } newObject = object(oldObject) F prototype constructor
  • 35.
    object function function object(o){ function F() {} F.prototype = o; return new F(); } newObject = object(oldObject) F prototype constructor oldObject
  • 36.
    object function function object(o){ function F() {} F.prototype = o; return new F(); } newObject = object(oldObject) F prototype newObject oldObject
  • 37.
    object function function object(o){ function F() {} F.prototype = o; return new F(); } newObject = object(oldObject) newObject oldObject
  • 38.
    Prototypal Inheritance var oldObject= { firstMethod: function () {...}, secondMethod: function () {...} }; var newObject = object(oldObject); newObject.thirdMethod = function () {...}; var myDoppelganger = object(newObject); myDoppelganger.firstMethod();
  • 39.
    Prototypal Inheritance • Thereis no limit to the length of the chain (except common sense). myDoppelganger = object(newObject); newObject oldObject
  • 40.
    Augmentation • Using theobject function, we can quickly produce new objects that have the same state and behavior as existing objects. • We can then augment each of the instances by assigning new methods and members.
  • 41.
    Public Method • APublic Method is a function that uses this to access its object. • This binding of this to an object happens at invocation time. • A Public Method can be reused with many "classes".
  • 42.
    Public Methods myObject.method =function (string) { return this.member + string; }; • We can put this function in any object at it works. • Public methods work extremely well with prototypal inheritance and with pseudoclassical inheritance.
  • 43.
    Singletons • There isno need to produce a class-like constructor for an object that will have exactly one instance. • Instead, simply use an object literal.
  • 44.
    Singletons var singleton ={ firstMethod: function (a, b) { ... }, secondMethod: function (c) { ... } };
  • 45.
    Functions are usedas • Functions • Methods • Constructors • Classes • Modules
  • 46.
    Module • Variables definedin a module are only visible in the module. • Functions have scope. • Variables defined in a function only visible in the function. • Functions can be used a module containers.
  • 47.
    Global variables areevil • Functions within an application can clobber each other. • Cooperating applications can clobber each other. • Use of the global namespace must be minimized.
  • 48.
    Singletons • The methodsof a singleton can enjoy access to shared private data and private methods.
  • 49.
    Singletons var singleton =function () { var privateVariable; function privateFunction(x) { ...privateVariable... } return { firstMethod: function (a, b) { ...privateVariable... }, secondMethod: function (c) { ...privateFunction()... } }; }();
  • 50.
    Applications are Singletons varAJAX = function () { var privateVariable; function privateFunction(x) { ...privateVariable... } return { firstMethod: function (a, b) { ...privateVariable... }, secondMethod: function (c) { ...privateFunction()... } }; }();
  • 51.
    Privacy • All membersof an object are public. • We want private variables and private methods. • Really.
  • 52.
    Privileged Method • APrivileged Method is a function that has access to secret information. • A Privileged Method has access to private variables and private methods. • A Privileged Method obtains its secret information through closure.
  • 53.
    Power Constructor • Putthe singleton module pattern in constructor function, and we have a power constructor pattern. 1. Make a new object somehow. 2. Augment it. 3. Return it.
  • 54.
    Power Constructor function powerConstructor(){ var that = object(oldObject), privateVariable; function privateFunction(x) { ... } that.firstMethod = function (a, b) { ...privateVariable... }; that.secondMethod = function (c) { ...privateFunction()... }; return that; }
  • 55.
    Power Constructor • Publicmethods (from the prototype) var that = object(oldObject); • • • • Private variables (var) Private methods (inner functions) Privileged methods No need to use new myObject = power_constructor();
  • 56.
    Parasitic Inheritance • Apower constructor calls another constructor, takes the result, augments it, and returns it as though it did all the work.
  • 57.
    Psudeoclassical Inheritance function Gizmo(id){ this.id = id; } Gizmo.prototype.toString = function () { return "gizmo " + this.id; }; function Hoozit(id) { this.id = id; } Hoozit.prototype = new Gizmo(); Hoozit.prototype.test = function (id) { return this.id === id; }
  • 58.
    Parasitic Inheritance function gizmo(id){ return { id: id, toString: function () { return "gizmo " + this.id; } }; } function hoozit(id) { var that = gizmo(id); that.test = function (testid) { return testid === this.id; }; return that; }
  • 59.
    Secrets function gizmo(id) { return{ toString: function () { return "gizmo " + id; } }; } function hoozit(id) { var that = gizmo(id); that.test = function (testid) { return testid === id; }; return that; }
  • 60.
    Shared Secrets function gizmo(id,secret) { secret = secret || {}; secret.id = id; return { toString: function () { return "gizmo " + secret.id; }; }; } function hoozit(id) { var secret = {}, that = gizmo(id, secret); that.test = function (testid) { return testid === secret.id; }; return that; }
  • 61.
    Super Methods function hoozit(id){ var secret = {}, that = gizmo(id, secret), super_toString = that.toString; that.test = function (testid) { return testid === secret.id; }; that.toString = function () { return super_toString.apply(that, []); }; return that; }
  • 62.
    Inheritance Patterns • PrototypalInheritance works really well with public methods. • Parasitic Inheritance works really well with privileged and private and public methods. • Pseudoclassical Inheritance for elderly programmers who are old and set in their ways.
  • 63.
    Working with theGrain • Pseudoclassical patterns are less effective than prototypal patterns or parasitic patterns. • Formal classes are not needed for reuse or extension. • Be shallow. Deep hierarchies are not effective.
  • 64.
    Performance • Provide agood experience. • Be respectful of our customer's time. • Hoare's Dictum: Premature optimization is the root of all evil.
  • 65.
    Efficiency • The firstpriority must always be correctness. • Optimize when necessary. • Consider algorithmic improvements O (n) v O (n log n) • Watch for limits. v O (n2)
  • 66.
    Minification vs Obfuscation • Reducethe amount of source code to reduce download time. • Minification deletes whitespace and comments. • Obfuscation also changes the names of things. • Obfuscation can introduce bugs. • Never use tools that cause bugs if you can avoid it. http://www.crockford.com/javascript/jsmin.html
  • 67.
    Code Conventions forthe JavaScript Programming Language http://javascript.crockford.com/code.html
  • 68.
    JSLint • JSLint canhelp improve the robustness and portability of your programs. • It enforces style rules. • It can spot some errors that are very difficult to find in debugging. • It can help eliminate implied globals. • Commandline versions. • In text editors and Eclipse.
  • 69.
    JSLint • Warning: JSLintwill hurt your feelings. • If you follow its advice, JSLint will make your programs better. •http://www.JSLint.com/
  • 70.
    JavaScript: A Language ofMany Contrasts Douglas Crockford Yahoo! http://javascript.crockford.com/ajaxworld.ppt