obj.prototype.__proto__ = events.EventEmitter.prototype
我有时看到上面的代码,我在谷歌上搜索它,他们说这一行将所有EventEmitter属性复制到obj。我也看到这样的代码:
obj.__proto__ = events.EventEmitter.prototype
所以我想知道它们是否相同?
我在这篇文章中看到了第一个用法,作者在其中给出了示例:
var events = require('events');
function Door(colour) {
this.colour = colour;
events.EventEmitter.call(this);
this.open = function()
{
this.emit('open');
}
}
Door.prototype.__proto__ = events.EventEmitter.prototype;
var frontDoor = new Door('brown');
frontDoor.on('open', function() {
console.log('ring ring ring');
});
frontDoor.open();
他解释道:
此行:
Door.prototype.__proto__ = events.EventEmitter.prototype;
将所有EventEmitter属性复制到Door对象。
至于第二种方式,我在hexo的源代码中看到了它,在init.js中,有代码:
var hexo = global.hexo = {
get base_dir(){return baseDir},
get public_dir(){return baseDir + 'public/'},
get source_dir(){return baseDir + 'source/'},
get theme_dir(){return baseDir + 'themes/' + config.theme + '/'},
get plugin_dir(){return baseDir + 'node_modules/'},
get script_dir(){return baseDir + 'scripts/'},
get scaffold_dir(){return baseDir + 'scaffolds/'},
get core_dir(){return path.dirname(dirname) + '/'},
get lib_dir(){return dirname + '/'},
get version(){return version},
get env(){return env},
get safe(){return safe},
get debug(){return debug},
get config(){return config},
get extend(){return extend},
get render(){return render},
get util(){return util},
get call(){return call},
get i18n(){return i18n.i18n},
get route(){return route},
get db(){return db}
};
hexo.cache = {};
// Inherits EventEmitter
hexo.__proto__ = EventEmitter.prototype;
// Emit "exit" event when process about to exit
process.on('exit', function(){
hexo.emit('exit');
});
语句不同。
与obj.prototype.__proto__ = events.EventEmitter.prototype
不同,我希望看到类似Constructor.prototype.__proto__ = events.EventEmitter.prototype
的东西(其中Constructor
是任何类型的构造函数,因此可以有任何名称。它们通常是大写的。)因为prototype
属性通常只在函数上可用,并且在定义为正则(非函数)对象的属性时没有任何特殊含义。
换句话说,给定代码的第一行中的obj
应该是一个(构造函数)函数才有意义,而且很少看到函数有obj
这样的通用变量名。
如果你能分享你找到确切第一句话的来源,这可能会澄清问题。
第二个例子是最简单的。没有涉及构造函数。hexo
是一个使用对象文字创建的普通对象。作者希望EventEmitter方法通过hexo
方法可用,因此他将EventEmitter.prototype
分配给__proto__
属性,这实际上改变了hexo
的原型。
第一个代码示例稍微复杂一些。在这里,作者希望确保Door
函数构建的任何对象都将提供对EventEmitter方法的访问。Door函数构造的任何对象都将得到Door.prototype
作为其原型。这个特殊的原型现在有EventEmitter作为它的原型,所以EventEmitter函数可以通过原型链的两个步骤来访问。
"将所有EventEmitter属性复制到Door对象。"-这个特殊的注释具有误导性。没有复制任何属性。唯一发生的事情就是这样。
door = new Door
door.on("open", function() { console.log("door has opened")})
door
的原型现在是Door.prototype
。如果在尝试访问某个属性(在本例中为on
)时未找到该属性,JS引擎将查看该原型。door
-Door.prototype
-的原型也没有定义on
,因此JS引擎将查看Door.prototype
是否有原型。它确实以events.EventEmitter.prototype
的形式存在。并且该对象确实定义了on
属性。
希望这能让事情变得更加清楚。Javascript原型继承相当棘手。
另请参阅有关设置的困惑。prototype。__proto__
prototype
属性通常在构造函数上找到,即创建新对象的函数。构造函数的prototype
是用作新实例化对象的原型的对象。
对象的__proto__
属性指向第一次实例化对象时用作原型的对象。它是非标准的,所以不能保证你的JavaScript引擎会支持它
在您的示例中,您可以看到它们指的是Door.prototype
和hexo.__proto__
。这里的关键区别在于Door
是一个构造函数,而hexo
是一个对象的实例。
然而,Door.prototype
是一个对象的实例,因此要获得其原型,需要使用__proto__
。
在这两种情况下,赋值的RHS都是构造函数,因此引用prototype
。
总之,如果您想要构造函数使用的原型,请使用prototype
。如果您想要实例化对象的原型,您可以使用__proto__
。
事实上,你最好使用Object.getPrototypeOf
。
源
JavaScript中的一切都是对象。每一个对象,它可能是一个函数,{}
,new Object()
,在JavaScript中都有一个名为[[Prototype]]
的内部属性。
[[Prototype]]
正是JavaScript中原型继承的原因。这个内部属性通过__proto__
暴露给程序员。这是非标准的。并非所有JS环境都支持此功能。
我们使用构造函数创建的对象是如何获得[[Prototype]]
的?
只有[[Class]]
为Function
的对象才能获得属性prototype
。这意味着JS引擎执行时声明的每个函数都会创建一个对象。其[[Class]]
被设置为Function
,并且属性prototype
被附加到此函数对象。
默认情况下,此原型是一个具有指向函数对象的属性constructor
的对象。
当上述函数作为新运算符(如new constructorFn()
)的一部分被调用时,JS引擎会创建一个对象,其[[Class]]
属性设置为Object
,[[Prototype]]
属性设置为构造函数的[[Prototype]]
所指向的对象。
由于这个新创建的对象属于Object
类,因此它不具有prototype
属性。
简而言之,__proto__
存在于每一个物体中。默认情况下,prototype
仅存在于[[Class]]
为Function
的对象中。这意味着只有函数(通过函数语句、函数表达式、Function
构造函数创建)才会具有此属性。