Javascript原型继承 - 后代互相覆盖 [英] Javascript prototypal inheritance - descendants override each other

查看:83
本文介绍了Javascript原型继承 - 后代互相覆盖的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在创建两个对象(Inherits),它们都从Base继承。
第二个对象的属性赋值会覆盖第一个对象中的值。

I'm creating two objects (Inherits), both inherit from Base. The second object's property assignment overrides the value in the first object.

有什么想法吗?如何进行正确的继承,以便Base类包含其继承后代的公共成员,但后代可以分配自己的值而不会相互干扰。

Any thoughts? How to make a proper inheritance so that Base class will contain common members for its inheritance descendants, but the descendants could assign values of their own without interfering each other.

var testParams1 = { title: "john" };
var testParams2 = { title: "mike" };

Function.prototype.inheritsFrom = function (baseClass)
{
    this.prototype = new baseClass;
    this.prototype.constructor = this;
    this.prototype.base = baseClass.prototype;
    return this;
};

function Base() {
    this.viewModel = {};
    this.viewModel.title = (function ()
    {
        var savedVal = "";
        return function (newVal)
        {
            if (typeof (newVal) === "undefined")
            {
                return savedVal;
            }
            savedVal = newVal;
        };
    })();
}
function Inherits(params) {
    this.viewModel.title(params.title);
}

Inherits.inheritsFrom(Base);

///// preparing code:
var testObj1 = new Inherits(testParams1);
var testObj2 = new Inherits(testParams2);

///// testing code:
equals(testObj1.viewModel.title(), testParams1.title, "first instance ok"); // returns "john"
equals(testObj2.viewModel.title(), testParams2.title, "second instance ok");  // also returns "john"


推荐答案

问题




  • Base 类构造函数只调用一次。

    this.prototype = new baseClass;

  • 特权方法将跨实例引用相同的对象,因为这些方法是在构造函数中创建(只调用一次)。

  • Problem(s)

    • The Base class constructor is called once and only once.
      this.prototype = new baseClass;
    • Privileged methods will refer to the same this object across instances because those methods are created within the constructor (which was called only once).

      • 如果你打算工作,你应该尽量避免修改原生原型(即。 Function.prototype )与你不拥有的JavaScript一起。

      • You should try to avoid modifying native prototypes (ie. Function.prototype) if you plan on working alongside JavaScript that you do not own.

      • 为每个创建的新实例调用构造函数和父构造函数。

      • 继承父原型链(不是父类的实例)。

      • 保持创建的实例数量的1:1比率原型链中构造函数的调用次数。

      请特别注意继承函数和 ParentClass.call(this,title); 线。
      要查找的构造函数是 ParentClass ChildClass

      Please pay special attention to the inherits function and the ParentClass.call(this, title); line. Constructors to look for are ParentClass and ChildClass

      /**
       * Allows a child constructor to safely inherit the parent constructors prototype chain.
       * @type {Function}
       * @param {!Function} childConstructor
       * @param {!Function} parentConstructor
       */
      function inherits(childConstructor, parentConstructor){
          var TempConstructor = function(){};
          TempConstructor.prototype = parentConstructor.prototype; // Inherit parent prototype chain
      
          childConstructor.prototype = new TempConstructor(); // Create buffer object to prevent assignments directly to parent prototype reference.
          childConstructor.prototype.constructor = childConstructor; // Reset the constructor property back the the child constructor
      };
      
      //////////////////////////////////////
      /** @constructor */
      function ParentClass(title) {
          this.setTitle(title);
      
          var randId_ = Math.random();
          /** @return {number} */
          this.getPrivlegedRandId = function()
              {return randId_;};
      };
      
      /** @return {string} */
      ParentClass.prototype.getTitle = function()
          {return this.title_;};
      
      /** @param {string} value */
      ParentClass.prototype.setTitle = function(value)
          {this.title_ = value;};
      
      //////////////////////////////////////    
      /**
       * @constructor
       * @param {string} title
       * @param {string} name 
       */
      ChildClass = function (name, title) {
          ParentClass.call(this, title); // Call the parent class constructor with the required arguments
      
          this.setName(name);
      }
      inherits(ChildClass, ParentClass); // Inherit the parent class prototype chain.
      
      /** @return {string} */
      ChildClass.prototype.getName = function()
          {return this.name_;};
      
       /** @param {string} value */
      ChildClass.prototype.setName = function(value)
          {this.name_ = value;};
      



      打下兔子洞



      对于那些人谁好奇为什么这样做只是记住它继承函数。

      当在实例级别找不到属性时,JavaScript将尝试通过搜索实例构造函数原型链来解析缺少的属性。如果在第一个原型对象中找不到该属性,它将搜索父原型对象,依此类推,直到 Object.prototype 。如果在 Object.prototype 中找不到它,则会抛出错误。

      When a property is not found at the instance level, JavaScript will try to resolve the missing property by searching through the instance constructors prototype chain. If the property is not found in the first prototype object, it will search the parent prototype object and so on all the way up to Object.prototype. If it can't find it within Object.prototype then an error will be thrown.

      // Bad
      var ChildConstructor = function(arg1, arg2, arg3){
          var that = new ParentConstructor(this, arg1, arg2, arg3);
          that.getArg1 = function(){return arg1};
          return that;
      }
      

      使用 new ChildConstructor创建的任何变量将返回 ParentConstructor 的实例。
      将不使用 ChildConstructor.prototype

      Any varible that is created using new ChildConstructor will return an instance of ParentConstructor. The ChildConstructor.prototype will be not be used.

      // Good
      var ChildConstructor = function(arg1, arg2, arg3){
          ParentConstructor.call(this, arg1, arg2, arg3);
      }
      

      现在正确调用构造函数和父构造函数。但是,只存在构造函数中定义的方法。父原型上的属性将不会被使用,因为它们尚未链接到子构造函数原型。

      Now constructor and the parent constructor is called appropriately. However, only methods defined within the constructor(s) will exist. Properties on the parent prototypes will not be used because they have not yet been linked to the child constructors prototype.

      // Bad
      ChildConstructor.prototype = new ParentConstructor();
      

      父构造函数将被调用一次或多次,具体取决于是否使用ParentConstructor.call(this)

      The parent constructor will either be called only once or one too many times depending on whether or not ParentConstructor.call(this) is used.

      // Bad
      ChildConstructor.prototype = ParentConstructor.prototype;
      

      虽然这在技术上有效但是对 ChildConstructor.prototype 也将被分配到 ParentConstructor.prototype ,因为对象是通过引用而不是通过副本传递的。

      Though this technically works, any assignments to ChildConstructor.prototype will also be assigned to ParentConstructor.prototype because Objects are passed by reference and not by copy.

      // Almost there
      var TempConstructor = function(){};
      TempConstructor.prototype = ParentConstructor.prototype;
      ChildConstructor.prototype = new TempConstructor();
      

      这允许您将属性分配给 ChildConstructor.prototype 因为它是临时匿名函数的一个实例。
      TempConstructor 的实例上找不到的属性将检查它的属性的原型链,因此您已成功继承了父原型。唯一的问题是 ChildConstructor.prototype.constructor 现在指向 TempConstructor

      This allows you to assign properties to ChildConstructor.prototype because it is an instance of a temporary anonymous function. Properties that are not found on the instance of TempConstructor will then check it's prototype chain for the property, so you have successfully inherited the parent prototype. The only problem is that ChildConstructor.prototype.constructor is now pointing to TempConstructor.

      // Good
      var TempConstructor = function(){};
      TempConstructor.prototype = ParentConstructor.prototype;
      ChildConstructor.prototype = new TempConstructor();
      ChildConstructor.prototype.constructor = ChildConstructor;
      



      All Together



      All Together

      var ParentConstructor = function(){
      };
      
      
      var ChildConstructor = function(){
          ParentConstructor.call(this)
      };
      
      var TempConstructor = function(){};
      TempConstructor.prototype = ParentConstructor.prototype;
      ChildConstructor.prototype = new TempConstructor();
      ChildConstructor.prototype.constructor = ChildConstructor;
      

      您已成功从父类继承!让我们看看我们是否可以做得更好。

      You've successfully inherited from the parent class! Let's see if we can do better.

      function inherits(childConstructor, parentConstructor){
          var TempConstructor = function(){};
          TempConstructor.prototype = parentConstructor.prototype; // Inherit parent prototype chain
      
          childConstructor.prototype = new TempConstructor(); // Create buffer object to prevent assignments directly to parent prototype reference.
          childConstructor.prototype.constructor = childConstructor; // Reset the constructor property back the the child constructor (currently set to TempConstructor )
      };
      
      
      var ParentConstructor = function(){
      };
      
      
      var ChildConstructor = function(){
          ParentConstructor.call(this)
      };
      inherits(ChildConstructor, ParentConstructor);
      

      这篇关于Javascript原型继承 - 后代互相覆盖的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆