this.constructor.prototype – 不能完全覆盖,但可以写个人道具吗?
TL; DR? 为什么我不能从构造函数中覆盖构造函数的原型?
我正在搞清楚我的原型inheritance模式。 我不喜欢原型如何通常是从构造函数的外部定义的,并且想要更好地逻辑地封装。
我发现我预计工作的那一个神奇的线不是。
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;
为此我可以创build一个简单的克隆函数来处理这个问题:
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; } }; }
幸运的是,在我的testing中,这项技术似乎运作良好,但我不确定是否有细节或性能的情况下,我可能会错过。
function Sphincter(){ extend(this.constructor.prototype).from(standardOrifice); //... }
为什么我不能从构造函数中覆盖构造函数的原型? 然而,我可以在构造函数之外? 写属性单独工作从一个构造函数?
为什么我不能从构造函数中覆盖构造函数的原型?
你可以,但为时已晚。 新的实例已经生成,从旧的原型inheritance。 也许阅读如何new
作品 。
我不喜欢原型如何通常从构造函数的外部定义。
就是这样。 你真的不应该在构造函数中设置原型 – 每次创build新实例时都会执行该原型。 这就是原型不应该是什么。 另请参见在构造函数中分配原型方法*为什么不?
并希望在逻辑上更好地封装的东西。
你可能想看看各种(揭示) 模块模式 。 或者甚至可能在一些Class
框架。
我目前正在寻找更具体的原因,我不应该采取我已经提出的模式。
它在Internet Explorer中不起作用。 它不适用于任何不支持__proto__
属性的ES5兼容环境。 你不应该使用它在现有的对象上设置一个原型。 相反,使用Object.create
(或其垫片) 正确的JavaScriptinheritance – 这就要求您覆盖构造函数之外的原型。
我的build议是在构造函数之外调用你的extend
助手,它仍然有一个很好的语法。
回答具体问题
为什么我不能从构造函数中覆盖构造函数的原型?
这是因为构造函数实际上是在对象已经被实例化之后调用的。 而且由于你的对象在你的构造函数触及任何东西之前就已经实例化了,所以你的构造函数也被赋予了一个“默认”的原型。
添加属性到this.constructor.prototype
似乎工作 – 因为你实际上操纵构造函数的预先分配的默认原型对象,所有的实例inheritance。
在我的例子中, this.constructor.prototype
最后提到了构造函数的默认赋值原型:如此完全覆盖它意味着从那时起所有新的实例都将拥有新的原型 – 正如Bergi所说,“太迟了” – 你的当前实例不会有这个新的原型,因为它仍然有旧的默认分配的原型,因为它已经被实例化了。
避免废话的一种更好的模式
我明白了,在我的问题中提出的技术根本不会。 这个问题本身通常是被误导的。 通过将Bergi的智慧与我个人的偏见结合起来,我提出了这种模式,以避免必须完全find原始问题的答案:
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,展开:
function extend(parentObject){ return { to: function(ChildConstructor){ for (key in parentObject) if (parentObject.hasOwnProperty(key)) ChildConstructor.prototype[key] = parentObject[key]; return ChildConstructor; } }; };
我用这个来testing它的工作原理:
// 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!"));