Douglas Crockford的“Javascript:The Good Parts”第5.5章

时间:2011-05-30 08:09:04

标签: javascript

我正在阅读书中的第5.5章。我仍然难以看到“我们可以使用章节中的可能性函数来组合各部分中的对象”。

对象是由具有“on”和“fire”功能的事件系统组成的吗?

本书以下部分的代码:

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

5 个答案:

答案 0 :(得分:7)

Crockford先生在这里的意思是你可以实现特定的功能,例如onfire函数,通过调用创建它们的函数对象将事件处理添加到任何对象({{1在这种情况下)将该对象作为参数。

这里的“部分”是eventuality功能对象中包含的“事件处理部分”。您可以想象添加其他功能的不同部分。这里的想法是您可以使用此系统将此功能添加到您需要的单个对象。这个概念称为Mixin(1)。

另请阅读第5章的最后一段:

  

通过这种方式,构造函数可以从一组零件中组装对象。 JavaScript的松散输入在这里是一个很大的好处,因为我们不会担心关注类的谱系的类型系统。

(1)谢谢你Zecc

答案 1 :(得分:1)

据我了解,本书这一部分的目的是说明JavaScript的强大功能 - 您可以轻松地使用各种“强大的JavaScript组件”构建一个对象。

正如他所说

  

例如,我们可以创建一个函数   可以添加简单的事件处理   任何对象的功能。它增加了一个   方法,火法和私人法   事件登记册

答案 2 :(得分:0)

无论哪种方式都可以。我是作者的忠实粉丝,他对我来说就像一个英雄。无论如何,javascript为我们提供的最好的功能之一就是动态对象。我们可以像我们想要的那样创建对象。

答案 3 :(得分:0)

以下是我自己的测试结果。如果您复制代码并将其粘贴到名为'test.js'的文件中,然后在命令行中通过'node test.js'(必须已经安装了节点)运行它,您将得到相同的结果。我的工作是通过跟踪带有不言自明的注释的流程向您展示如何利用eventuality()。

唯一我不理解的地方是线路; “fund = this [func]”(以“???”作为评论)。看来“func = registry [func]”对我来说更有意义,因为注册表对象是处理程序注册的地方,而不是eventuality函数对象(即'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);

以下是输出:

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"

答案 4 :(得分:0)

我进一步修改了Daniel C Deng的例子,以进一步解释这个[func]的使用。此代码在Chrome中的JavaScript控制台中运行。

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.com/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);

这是输出:

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.