TL; DR? 为什么我不能在构造函数中覆盖构造函数的原型?
我正在弄清楚我的原型继承模式。我不喜欢原型通常是从构造函数外部定义的,并且想要在逻辑上更好地封装事物。
我发现我期望工作的一条神奇的线路没有。
function Orifice(){
this.exhaust=function(){};
this.ingest=function(){};
}
var standardOrifice = new Orifice();
function Sphincter(){
this.constructor.prototype = standardOrifice; // <-- does not work
this.relax=function(){};
this.tighten=function(){};
}
有趣的是,我可以将单个属性写入this.constructor.prototype
,但我不能像构造函数定义之外那样覆盖整个原型对象。
这样的东西很有效:
this.constructor.prototype.exhaust = standardOrifice.exhaust;
this.constructor.prototype.ingest = standardOrifice.ingest;
我可以创建一个简单的克隆函数来处理这个问题:
function extend(target){
return {
from: function(obj){
target.__proto__ = obj.constructor.prototype;
for (key in obj) if (obj.hasOwnProperty(key)) target[key]=obj[key];
return target;
}
};
}
值得庆幸的是,到目前为止,在我的测试中,这种技术似乎运行良好,但我不确定是否有可能缺少的细节或性能案例。
function Sphincter(){
extend(this.constructor.prototype).from(standardOrifice);
//...
}
为什么我不能在构造函数中覆盖构造函数的原型?但是我可以在构造函数之外吗?单独编写属性是否在构造函数中起作用?
答案 0 :(得分:5)
为什么我不能在构造函数中覆盖构造函数的原型?
你可以,但为时已晚。新实例已经生成,继承自旧原型。也许阅读how new
works。
我不喜欢原型通常是从构造函数外部定义的。
就是这样。你实际上不应该在构造函数中设置原型 - 它会在每次创建新实例时执行。这就是原型不应该是什么。另请参阅Assigning prototype methods *inside* the constructor function - why not?
并希望在逻辑上更好地封装内容。
您可能希望了解各种(揭示)module patterns。或者甚至可能在某个Class
框架上。
我目前正在寻找更具体的理由,我不应该以我一直呈现的模式出发。
它在Internet Explorer中不起作用。它不适用于任何不支持__proto__
属性的ES5兼容环境。你永远不应该使用它在现有对象上设置原型。相反,对Object.create
使用Correct javascript inheritance(或其垫片) - 这要求您在构造函数之外覆盖原型。
我的建议是在构造函数之外调用你的extend
帮助器,它仍然有一个很好的语法。
答案 1 :(得分:1)
为什么我不能在构造函数中覆盖构造函数的原型?
这是因为在对象已经被实例化之后,构造函数实际上被称为。并且由于您的对象已经设法在构造函数触及任何内容之前实例化,因此您的构造函数也已经被赋予了“默认”原型。
向this.constructor.prototype
添加属性似乎有效 - 因为您实际上正在操纵构造函数的预分配默认原型对象,所有实例都继承该对象。
在我的示例中,this.constructor.prototype
最终引用了构造函数的默认分配原型:所以完全覆盖它意味着从那一刻开始的所有新实例将具有该新原型 - - 正如Bergi所说,“为时已晚” - 您当前的实例将没有新的原型,因为它仍然具有旧的默认分配原型,因为它已经被实例化了。
我已经明白,我的问题中提出的技术根本不会这样做。问题本身通常是错误的。通过将Bergi的智慧与我个人的偏见相结合,我想出了这种模式,以避免必须完全找到原始问题的答案:
function extend(p){
return { to: function(C){ for (k in p) if (p.hasOwnProperty(k))
C.prototype[k]=p[k]; return C; } };
};
var orifice = new function Orifice(){
this.exhaust=function(){};
this.ingest=function(){};
};
var Sphincter = extend(orifice).to(function Sphincter(){
this.relax=function(){};
this.tighten=function(){};
});
这是扩展功能,扩展名为:
function extend(parentObject){
return {
to: function(ChildConstructor){
for (key in parentObject)
if (parentObject.hasOwnProperty(key))
ChildConstructor.prototype[key] = parentObject[key];
return ChildConstructor;
}
};
};
我用它来测试它的工作原理:
// TESTING
var s=new Sphincter();
var tests=['relax','tighten','exhaust','ingest'];
for (var i in tests) console.log("s."+tests[i]+"() is "+(tests[i]in s?"present :)":"MISSING!"));