Douglas Crockford - Advanced JavaScript
*Inheritance
*Modules
*Debugging
*Effiency
*JSON
Inheritance
Inheritance is object-oriented code reuse.
Two Schools:
Classical
Prototypal - which JavaScript is about the only instance.
Classical Inheritance
Objects are instances of classes.
A class inherits from another class.
Prototypal Inheritance
Class-free - No classes
Objects inherit from objects.
An object contains a secret link to another object from which it inherits properties.
Mozilla calls it proto .
var newObject = object(oldObject);
var oldObject = { |
Prototypal Inheritance
The way it works is if we try to access a property of an object,
and that object lacks that property, then we follow the linkage
to the object that it inheritance from to see if it has it,
if it does, than it provides the access.
If the access fails, then we can continue the search from this one.
Alternative, it stops at Object.prototype
because Object.prototype
is the end of the chain.
If an object has a
foo
property, then the chain will not be consulted when accessing memberfoo
.newObject.foo newObject[‘foo’]
If access of a member of newObject fails, then search for the member in oldObject.
If that fails, then search for the member in Object.prototype.
newObject -> oldObject
Prototypal Inheritance
Changes in
oldObject
may be immediately visible innewObject
.Changes to
newObject
have no effect onoldObject
.
Prototypal Inheritance
oldObject
can be the prototype for an unlimited number of objects which will all inherit its properities.
Prototypal Inheritance
newObject
can be the prototype for an unlimited number of even newer objects.There is no limit to the length of the chain (except common sense).
Augmentation
Using the
object
function, we can quickly produce new objects that have the same state and behavior as exising objects.We can then augment each of the instances by assigning new methods and members.
Pseudoclassical
A prototypal inheritance language should have an operator like the
object
function, which makes a new object using an existing object as its prototype.JavaScript instead uses operators that look classical, but behave prototypally.
They tried to have it both ways.
Pseudoclassical
Three mechanisms:
Constructor
functions.The
new
operator.The
prototype
member of functions.
new
operator
function Constructor() { |
Constructor
When functions are designed to be used with
new
, they are called
constructors.Constructors are used to make objects of a type or class/seudoclass.
JavaScript’s notation can get a little strange because it is trying to look like the old familiar classical pattern, while also trying to be something really different.
new
operator
new Constructor()
returns a new object with a link toConstructor.prototype
.
var newObject = new Constructor();
new operator
The Constructor()
function is passed the new object in the this
variable.
This allows the Constructor
function to customize the new object.
Warning
The
new
operator is required when calling a Constructor.If
new
is ommited, the global object is clobbered by the constructor,this
would be the global object.
and then the global object is returned instead of a new instance.
Prototype
When a function object is created, it is given a
prototype
member which is an object containing aconstructor
member which is a reference to the function object.You can add other members to function’s
prototype
. These members will be linked into objects that are produced by calling the function with thenew
operator.This allows for adding constants and methods to every object produced, without the objects having to be enlarged to contain them.
Differential Inheritance.
method
method
Function.prototype.method = |
Constructor.method('first_method',
function (a, b) {...}).
method('second_method',
function (c) {...});
Pseudoclassical Inheritance
Classical Inheritance can be simulated by assigning an object created by one constructor to the prototype member of another.
This does not work exactly like the classical model.
function BiggerConstructor() {}; |
Example
function Gizmo(id) { |
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.
function Hoozit(id) { |
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) { |
Public Method
- A Public Method is a function that uses
this
to access its object. - A Public Method can be reused with many “classes”.
Public Methods
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, simple use an object literal.
Singletonsvar singleton = {
firstMethod: function (a, b) {
...
},
secondMethod: function (c) {
...
}
};
Singletons
- The methods of a singleton can enjoy access to shared private data and private methods.
Functions
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.
Another way to write Singletonsvar singleton = function () {
var privateVariable;
function privateFunction(x) {
... privateVariable ...
}
return {
firstMethod: function (a, b) {
... privateVariable ...
},
secondMethod: function (c) {
...privateFunction() ...
}
};
}();
Applications are Singletons
YAHOO.MyProperty = function () { |
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.
- Make a new object somehow.
- Augment it.
- Return it.
function powerConstructor() { |
Power Constructor
Public methods (from the prototype)
var that = object(my_base);Private variables (var)
Private methods (inner functions)
Privileged methodss (that…)
No need to use
new
myObject = power_constructor();
Parasitic Inheritance
A power constructor calls another constructor, takes the result, augments it, and return it as though it did all the work.
function symbol(s, p) { |
Pseudoclassical Inheritance
function Gizmo(id) { |
Parasitic Inheritance
function gizmo(id) { |
Secrets
function gizmo(id) { |
Shared Secrets
function gizmo(id, secret) { |
Super Methodsfunction boozit(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 that prototypal patterns or parasitic patterns.
Formal classes are not needed for reuse or extension.
Be shallow. Deep hierarchies are not effective.
later
method
The later
method causes a method on the object to be invoked in the future.
my_object.later(1000, “erase”, true);
later
methodObject.prototype.later =
function (msec, method) {
var that = this,
args = Array.prototype.slice.apply(arguments, [2]);
if (typeof method === 'string') {
method = that[method];
}
setTimeout(function () {
method.apply(that, args);
}, msec);
return that;
};
Multiples
- when assigning functions in a loop, be aware that all of the functions are bound to the same closure.
- This can be avoided by using a factor function to produce unique bindings.
Multiples
for (i ...) { |