【问题标题】:javascript prototyped inheritance and object propertiesjavascript原型继承和对象属性
【发布时间】:2012-01-04 09:15:44
【问题描述】:

我正在尝试将原型继承应用于 Javascript 中的函数。这一切都很简单,甚至在Wikipedia's javascript lemma 中有描述。如果我的属性是简单的 javascript 类型,它就可以工作:

function Person() {
    this.age = 0;
    this.location = {
        x: 0,
        y: 0,
        absolute: false
    };
};

function Employee() {};

Employee.prototype = new Person();
Employee.prototype.celebrate = function () {
    this.age++;
}

var pete = new Employee();
pete.age = 5;
pete.celebrate();
var bob = new Employee();
bob.celebrate();
console.log("bob is " + bob.age + " pete is " + pete.age);

使用Employee.prototype = new Person();,Person 的所有属性和(原型)方法都由 Employee 继承,这是继承的基础。

这按预期工作:bob is 1 pete is 6

现在我开始摆弄皮特的位置(庆祝之后)

pete.celebrate();
pete.location.absolute=true;

显示 bob.location.absolute 显示:true,这很不直观(我没有触摸 bob 的位置,所以我希望它具有在 Person 中声明的初始值)并破坏了我的解决方案。

在我最初的理解中,这应该是错误的。我确实意识到我可能应该从初始 Person 克隆位置对象,但我不确定在哪里或如何执行此操作。 如果有更好的继承技术?

【问题讨论】:

    标签: javascript inheritance


    【解决方案1】:

    当你实例化一个新的 Employee 时,Person 的所有属性都会被复制。由于这是一个浅拷贝,pete 和 bob 共享同一个位置对象。对于您的问题,似乎没有很好的解决方案。您可以使用框架或像这样进行 hack:

    function Employee() { Person.apply(this); };
    

    这会在 this 对象的上下文中调用 Person 构造函数。

    MDC 对此有更多信息:https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Function/apply

    【讨论】:

      【解决方案2】:

      继承时不要运行 Person 构造函数,Employee 不应该 甚至有一个.location,因为它不在Person.prototype

      function createObject( fn ){
          function f(){}
          f.prototype = fn.prototype;
          return new f;
      }
      

      然后:

      Employee.prototype = createObject( Person );
      

      这将正确继承而没有副作用(运行构造函数)。

      你只能在子构造函数中运行父构造函数:

      function Employee() {
      Person.apply( this, arguments );
      }
      

      【讨论】:

      • 使用 createObject(Person) 代替 new Person() 有什么好处?它只增加了一层原型间接。
      • @Kosta 避免在继承时运行构造函数的副作用。构造函数中通常包含初始化代码,当您不实例化任何内容时,您不想运行这些代码。 new Employee 仍然是 instanceof Person,因为 Person.prototypef.prototype 都指向同一个对象。
      • 但您仍在 createObject() 中运行构造函数(一次)。此外,您正在 Employee() 中运行构造函数(在每个实例化上)。你能举一个 createObject() 有用的例子吗?
      • @Kosta 不,我不是,我正在运行一个空的构造函数,因此没有副作用。您也可以为此使用 .__proto__Object.create,但并非所有浏览器都支持它们。
      【解决方案3】:

      我遇到了类似的问题。我最终为内部对象使用了一个单独的构造函数。

      function engine(cc, fuel) {
             this.cc = cc; 
             this.fuel = fuel
      }
      
      function car(type, model, cc, fuel) {
             this.type = type; 
             this.model = model;
             this.engine = new engine(cc, fuel);
      }
      
      
      var mycar = new car("sedan", "toyota corolla", 1500, "gas");
      console.log(mycar.type);
      //sedan
      console.log(mycar.engine.cc);
      //1500
      

      如果我在“engine”或“car”构造函数的原型上有任何方法,它们仍然可用。但是,我并不是从 OOP 意义上的“引擎”类派生“汽车”类。我不需要。 “引擎”被用作“汽车”的一个组成部分。

      同时,对于继承,我更喜欢使用 ECMAScript 5 中包含的新方法,这意味着使用 Object.create、Object.defineProperties 等。即使在 IE9 中也支持它们。在此之前,我使用了 Kosta 建议的相同的 'apply()' 方法。

      【讨论】:

        猜你喜欢
        • 2023-03-16
        • 1970-01-01
        • 1970-01-01
        • 2014-11-26
        • 2013-03-05
        • 2015-01-17
        • 2016-02-15
        • 1970-01-01
        • 2013-07-17
        相关资源
        最近更新 更多