this.constructor.prototype -- 不能完全覆盖,但可以写个别props?

IT技术 javascript
2021-02-03 03:48:47

特尔;博士? 为什么我不能从构造函数内部覆盖构造函数的原型?

我正在弄清楚我的原型继承模式。我不喜欢通常如何从构造函数外部定义原型,并希望在逻辑上更好地封装事物。

我发现我希望工作的一条神奇的线路没有。

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

为什么我不能从构造函数内部覆盖构造函数的原型?然而我可以在构造函数之外吗?并在构造函数中单独编写属性?

2个回答

为什么我不能从构造函数内部覆盖构造函数的原型?

你可以,但为时已晚。新实例已经生成,继承自旧原型。也许阅读如何new工作

我不喜欢原型通常是如何从构造函数外部定义的。

就是那样子。真的不应该从构造函数中设置原型 - 每次创建新实例时都会执行它。这特别是原型不应该是什么。另请参阅在构造函数中*内部*分配原型方法 - 为什么不呢?

并希望在逻辑上更好地封装事物。

您可能想看看各种(揭示)module模式或者甚至可能在某个Class框架中。

我目前正在寻找更具体的原因,我不应该继续我一直在展示的模式。

它在 Internet Explorer 中不起作用。它不会在任何不支持该__proto__属性的ES5 兼容环境中工作您永远不应该使用它在现有对象上设置原型。相反,使用Object.create(或其垫片)进行正确的 javascript 继承- 这要求您覆盖构造函数之外的原型。

我的建议是在它extend的构造函数之外调用你的助手,它仍然有一个很好的语法。

以我的方式在构造函数中扩展原型有什么问题吗?它只是非常规,还是实际上会导致问题?我知道在构造函数中定义原型的函数(对于每个实例)是一个常见的错误,但我认为我没有这样做——共享函数只声明一次。也许存在性能问题,与 extend() 函数所需的时间一样长?我猜它不会太糟糕;我认为 Resig 的解决方案在某处做了类似的事情。
2021-03-20 03:48:47
我不小心提早提交了我的评论,试图添加一个换行符 :)——我编辑了我的完整评论。
2021-03-23 03:48:47
多亏你的话,我想我开始掌握了。完全覆盖this.constructor.prototype实际上是设置将用于下一个实例的原型因为我们的构造函数实际上是在对象实例化之后调用的,所以它已经被赋予了“默认”原型(或由我们最后一个实例的 extend() 调用定义的原型,导致我们重新覆盖每个实例的每个扩展属性)。该死的, 我希望你不是那么正确。简直太好看了吧……</idealistic-dreams>
2021-03-27 03:48:47
我添加了一行(在此粘贴中)使 extend() 函数具有幂等性——它现在this.constructor.prototype只在第一次扩展希望这可以消除性能问题,但这并不一定能阻止该技术以我尚未预见的其他方式表现不佳。我承认——性感的语法是一种诱惑。我目前正在寻找更具体的原因,我不应该继续我一直在展示的模式。
2021-04-08 03:48:47
非常规:是的。导致问题:例如您遇到的问题。错误:是的,从性能的角度来看——原型只需要设置一次(很好,你至少没有重新创建函数)。您在“Resig 的解决方案”(哪一个?)中在哪里看到这一点?
2021-04-09 03:48:47

对特定问题的回答

为什么我不能从构造函数内部覆盖构造函数的原型?

这是因为构造函数实际上是您的对象已经被实例化之后被调用的并且由于您的对象在您的构造函数接触任何东西之前已经成功实例化,您的构造函数也已经被分配了一个“默认”原型。

添加属性this.constructor.prototype似乎有效——因为您实际上是在操作构造函数的预先分配的默认原型对象,您的所有实例都继承自该对象。

在我的示例中,this.constructor.prototype最终指的是构造函数的默认分配原型:完全覆盖这意味着从那一刻起所有新实例都将具有该新原型——正如贝尔吉所说,“太晚了”——你当前的实例将没有那个新原型,因为它仍然具有旧的默认分配原型,因为它已经被实例化。

避免废话的更好模式

我开始明白,我的问题中提出的技术根本行不通。这个问题本身通常是被误导的。通过将 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!"));