我非常喜欢将函数导出为JavaScript模块的主要API的模式。原因是在JS中,函数基本上可以完成典型对象可以执行的任何操作,然后执行一些操作。
所以这对我来说很典型:
function stuff() {}
function thing() { /* shortcut or default behavior */ }
thing.stuff = stuff;
module.exports = thing;
现在我遇到了thing
行为像EventEmitter的实例的情况。我不希望它成为构造函数。
为什么呢?好的thing
将真正沿着osPreferences
行,用一些选项调用它会将数据保存到磁盘。用户实例化它没有任何意义。由于您的计算机一次只能尊重一组偏好设置,因此new OSPreferences()
不会有太大用处。
然而,更改可以在我的API之外的任何时间发生。因此,有一个巨大的好处:
osPreferences.on('change', fn);
所以问题是,什么是吸收EventEmitter 实例行为的可靠模式?简单地循环遍历一次性实例的所有属性并将它们复制到目标函数是否足够好?是否值得尝试模仿继承与非继承的设置?考虑到默认this
会被更改,是否有任何奇怪的案例需要考虑?还是有更好,更明智的方式?
答案 0 :(得分:1)
循环并复制原始对象的方法和属性可能会失败,具体取决于EventEmitter的实现方式。当大量使用闭包来隐藏属性时,这种方法很可能会失败。
在我看来,最好的方法是直接在函数实例上设置原型。在您的示例中,它将类似于:
var OSPreferences = function(){
// ...
};
Object.setPrototypeOf(OSPreferences, new EventEmitter());

答案 1 :(得分:1)
简单地循环遍历一次性实例的所有属性并将它们复制到目标函数是否足够好?
是。您甚至不需要创建一次性实例,只需将所有EventEmitter.prototype
方法复制到您的函数上,然后将EventEmitter
应用于该函数。
function osPreferences() { … }
for (var p in EventEmitter.prototype)
osPreferences[p] = EventEmitter.prototype[p];
EventEmitter.call(osPreferences);
是否值得尝试模仿继承与非继承的设置?
不是真的。你坚持单独使用你的api,所以你根本不需要任何继承。
考虑到默认
this
会被更改,是否有任何奇怪的案例需要考虑?
不,EventEmitter
is coded quite defensively。当然,你的听众可能会发现它很不寻常......
答案 2 :(得分:0)
ES6 class syntax是子类化最优雅的解决方案。
let EventEmitter = require('events'); //or `require('events').EventEmitter` in nodejs
Class osPreferences extends EventEmitter{
constructor(){
super();
console.log(this);
}
}
let osp = new osPreferences();
osp.on('change',function(){
console.log('osPreferences changed');
});
osp.emit('change');
不幸的是,最新的Node版本不支持类语法。您必须改为使用iojs。