I was reading Ch 5.5 of the book in title. I have still have trouble in seeing how "We can pose objects out of sets of parts" using the eventuality function in the chapter.
Are objects to be posed by a event system with the "on" and "fire" functions ?
Code from the section of the book below:
var eventuality = function (that) {
var registry = {};
that.fire = function (event) {
// Fire an event on an object. The event can be either
// a string containing the name of the event or an
// object containing a type property containing the
// name of the event. Handlers registered by the 'on'
// method that match the event name will be invoked.
var array,
func,
handler,
i,
type = typeof event === 'string' ?
event : event.type;
// If an array of handlers exist for this event, then
// loop through it and execute the handlers in order.
if (registry.hasOwnProperty(type)) {
array = registry[type];
for (i = 0; i < array.length; i += 1) {
handler = array[i];
// A handler record contains a method and an optional
// array of parameters. If the method is a name, look
// up the function.
func = handler.method;
if (typeof func === 'string') {
func = this[func];
}
// Invoke a handler. If the record contained
// parameters, then pass them. Otherwise, pass the
// event object.
func.apply(this,
handler.parameters || [event]);
}
}
return this;
};
that.on = function (type, method, parameters) {
// Register an event. Make a handler record. Put it
// in a handler array, making one if it doesn't yet
// exist for this type.
var handler = {
method: method,
parameters: parameters
};
if (registry.hasOwnProperty(type)) {
registry[type].push(handler);
} else {
registry[type] = [handler];
}
return this;
};
return that;
}
I was reading Ch 5.5 of the book in title. I have still have trouble in seeing how "We can pose objects out of sets of parts" using the eventuality function in the chapter.
Are objects to be posed by a event system with the "on" and "fire" functions ?
Code from the section of the book below:
var eventuality = function (that) {
var registry = {};
that.fire = function (event) {
// Fire an event on an object. The event can be either
// a string containing the name of the event or an
// object containing a type property containing the
// name of the event. Handlers registered by the 'on'
// method that match the event name will be invoked.
var array,
func,
handler,
i,
type = typeof event === 'string' ?
event : event.type;
// If an array of handlers exist for this event, then
// loop through it and execute the handlers in order.
if (registry.hasOwnProperty(type)) {
array = registry[type];
for (i = 0; i < array.length; i += 1) {
handler = array[i];
// A handler record contains a method and an optional
// array of parameters. If the method is a name, look
// up the function.
func = handler.method;
if (typeof func === 'string') {
func = this[func];
}
// Invoke a handler. If the record contained
// parameters, then pass them. Otherwise, pass the
// event object.
func.apply(this,
handler.parameters || [event]);
}
}
return this;
};
that.on = function (type, method, parameters) {
// Register an event. Make a handler record. Put it
// in a handler array, making one if it doesn't yet
// exist for this type.
var handler = {
method: method,
parameters: parameters
};
if (registry.hasOwnProperty(type)) {
registry[type].push(handler);
} else {
registry[type] = [handler];
}
return this;
};
return that;
}
Share
Improve this question
edited May 30, 2011 at 8:33
isNaN1247
18.1k13 gold badges74 silver badges119 bronze badges
asked May 30, 2011 at 8:09
user670800user670800
1,1151 gold badge11 silver badges16 bronze badges
4
- 3 It would be nice of you could also post some code so that people can help you who don't have the book ;) – Felix Kling Commented May 30, 2011 at 8:11
- 3 The free chapter can be found @ yuiblog./assets/pdf/crockford-good-parts-ch-5.pdf – KooiInc Commented May 30, 2011 at 8:17
- 2 For those with the book its page 55 - heading is 'Parts' – isNaN1247 Commented May 30, 2011 at 8:20
-
1
What exactly is your question again? The methods
fire
andon
are added to the object at run time (dynamically). I think that is the whole point. – Felix Kling Commented May 30, 2011 at 8:35
5 Answers
Reset to default 7What Mr. Crockford means here is that you can implement specific functionality such as the on
and fire
functions that add event processing to any object by calling the function object that creates them (eventuality
in this case) with that object as parameter.
The "part" here is an "event processing part" embodied in the eventuality
function object. You could imagine different parts that add other functions. The idea here is that you can use this system to add this functionality to individual objects where you need it. This concept is called a Mixin(1).
Also read the final paragraph of chapter 5:
In this way a constructor could assemble objects from a set of parts. JavaScript's loose typing is a big benefit here because we are not burdened with a type system that is concerned about the lineage of classes.
(1) Thank you Zecc.
As I understand it, the point of this section of the book is to illustrate the power of JavaScript - in that you could build an object with all the various 'powerful ponents of JavaScript' easily.
As he says
For example, we can make a function that can add simple event processing features to any object. It adds an on method, a fire method, and a private event registry
either way is possible. i'm a huge fan of the author and he's like a hero to me. anyway, one of the best feature javascript offers us is the dynamic object. we can create object(s) as when do we desire it.
The following is my own test result. If you copy the code and paste them to a file named 'test.js', then run it on the mand line by 'node test.js' (must have already installed node), you will get the same result. My effort is to show you how to make use of eventuality() by tracing the flow with self-explanatory ments.
The only place I don't understand is the line; "fund = this[func]" (with "???" as the ment). It seems that "func = registry[func]" makes more sense to me, since the registry object is where the handler is registered, not the eventuality function object (i.e., the 'this').
var eventuality = function(that) {
var registry = {};
that.fire = function(event) {
var type = typeof event === 'string' ? event : event.type;
console.log('fire(): fired on event, "' + type + '"');
if (registry.hasOwnProperty(type)) {
var array = registry[type];
for (var i = 0; i < array.length; ++i) {
var handler = array[i];
console.log('fire(): handler found at loop ' + i);
var func = handler.method;
var pars = handler.parameters;
if (typeof func === 'string') {
console.log('fire(): the found func is a string');
func = this[func]; // ???
} else {
// Invoke the handler with parameters.
console.log('fire(): the found method is NOT a string');
func.apply(this, [pars]);
}
}
}
return this;
};
that.on = function(type, method, parameters) {
// Register an event. Make a handler record. Put it in a handler array, making
// one if it doesn't yet exist for this type.
var handler = {
method: method,
parameters: parameters
};
if (registry.hasOwnProperty(type)) {
// If already registered:
registry[type].push(handler);
} else {
// If it's first time:
console.log('on(): "' + type + '" event registered');
registry[type] = [handler];
}
return this;
}
return that;
};
var dog_is_hungry = {
type: 'is_hungry'
};
var dog_needs_to_poo = {
type: 'needs_to_poo'
};
var dog_methods = {
feed: function() {
console.log('Event processed by the handler, dog_methods.feed(): ');
for (var i = 0; i < arguments.length; ++i) {
console.log(' Feed the dog with the "' + arguments[i].food + '"');
}
},
walk: function() {
console.log('Event processed by the handler, dog_methods.walk(): ');
for (var i = 0; i < arguments.length; ++i) {
console.log(' Walk the dog to the "' + arguments[i].place + '"');
}
}
};
var myDog = {
name: 'Lucky',
age: 2
}
var myDogEHM = eventuality(myDog); // EHM - events handling manager
console.log('My dog is named ' + myDogEHM.name);
console.log('My dog is aged ' + myDogEHM.age);
// Register the event-handlers
myDogEHM.on(dog_is_hungry.type, dog_methods.feed, {
food: 'rice and meat'
});
myDogEHM.on(dog_needs_to_poo.type, dog_methods.walk, {
place: 'park'
});
// Events to be handled
myDogEHM.fire(dog_is_hungry);
myDogEHM.fire(dog_needs_to_poo);
The following is the output:
My dog is named Lucky
My dog is aged 2
on(): "is_hungry"
event registered
on(): "needs_to_poo"
event registered
fire(): fired on event, "is_hungry"
fire(): handler found at loop 0
fire(): the found method is NOT a string
Event processed by the handler, dog_methods.feed():
Feed the dog with the "rice and meat"
fire(): fired on event, "needs_to_poo"
fire(): handler found at loop 0
fire(): the found method is NOT a string
Event processed by the handler, dog_methods.walk():
Walk the dog to the "park"
I have further modified Daniel C Deng's example, to further explain the use of this[func]. This code runs in the JavaScript console in Chrome.
var eventuality = function(that) {
var registry = {};
that.fire = function(event) {
var type = typeof event === 'string' ? event : event.type;
console.log('fire(): fired on event, "' + type + '"');
if (registry.hasOwnProperty(type)) {
var array = registry[type];
for (var i = 0; i < array.length; ++i) {
var handler = array[i];
console.log('fire(): handler found at loop ' + i);
var func = handler.method;
var pars = handler.parameters;
if (typeof func === 'string') {
console.log('fire(): the found func is a string');
func = dog_methods_2[func];
//javascript turn string into object reference.
//https://stackoverflow./questions/10953303/javascript-interpret-string-as-object-reference
}
// Invoke the handler with parameters.
//console.log('fire(): the found method is NOT a string');
func.apply(this, [pars]);
}
}
return this;
};
that.on = function(type, method, parameters) {
// Register an event. Make a handler record. Put it in a handler array, making
// one if it doesn't yet exist for this type.
var handler = {
method: method,
parameters: parameters
};
if (registry.hasOwnProperty(type)) {
// If already registered:
registry[type].push(handler);
} else {
// If it's first time:
console.log('on(): "' + type + '" event registered');
registry[type] = [handler];
}
return this;
}
return that;
};
var dog_is_hungry = {
type: 'is_hungry'
};
var dog_needs_to_poo = {
type: 'needs_to_poo'
};
var dog_is_thirsty = {
type: 'needs_to_drink'
};
var dog_methods = {
feed: function() {
console.log('Event processed by the handler, dog_methods.feed(): ');
for (var i = 0; i < arguments.length; ++i) {
console.log(' Feed the dog with the "' + arguments[i].food + '"');
}
},
walk: function() {
console.log('Event processed by the handler, dog_methods.walk(): ');
for (var i = 0; i < arguments.length; ++i) {
console.log(' Walk the dog to the "' + arguments[i].place + '"');
}
},
strings: ["drink"]
};
var dog_methods_2 = {
drink: function() {
console.log(" The dog drinks " + arguments[0].drink + ".");
}
}
var myDog = {
name: 'Lucky',
age: 2
}
var myDogEHM = eventuality(myDog); // EHM - events handling manager
console.log('My dog is named ' + myDogEHM.name);
console.log('My dog is aged ' + myDogEHM.age);
// Register the event-handlers
myDogEHM.on(dog_is_hungry.type, dog_methods.feed, {
food: 'rice and meat'
});
myDogEHM.on(dog_needs_to_poo.type, dog_methods.walk, {
place: 'park'
});
// Events to be handled
myDogEHM.fire(dog_is_hungry);
myDogEHM.fire(dog_needs_to_poo);
myDogEHM.on(dog_is_thirsty.type, dog_methods.strings[0], {
drink: 'water'
});
myDogEHM.fire(dog_is_thirsty);
This is the output:
My dog is named Lucky
My dog is aged 2
on(): "is_hungry" event registered
on(): "needs_to_poo" event registered
fire(): fired on event, "is_hungry"
fire(): handler found at loop 0
Event processed by the handler, dog_methods.feed():
Feed the dog with the "rice and meat"
fire(): fired on event, "needs_to_poo"
fire(): handler found at loop 0
Event processed by the handler, dog_methods.walk():
Walk the dog to the "park"
on(): "needs_to_drink" event registered
fire(): fired on event, "needs_to_drink"
fire(): handler found at loop 0
fire(): the found func is a string
The dog drinks water.