如何允许对象从类中继承成员?

时间:2017-01-18 23:44:25

标签: javascript java static-members prototype-programming

这个问题是关于Javascript的,但我学到的第一种编程语言是Java,所以我最容易与之相关。

在Java中,对象可以访问静态成员,如Oracle的文章Understanding Class Members所示:

public class Bicycle {
  // INSTANCE fields
  private int cadence;
  private int gear;
  private int speed;

  // CONSTRUCTOR
  constructor Bicycle(c,g,s) { /*...*/ }

  //...

  // STATIC fields
  private static int numberOfBicycles = 0;
}
  

您也可以使用对象引用来引用静态字段   myBike.numberOfBicycles

除了可以访问静态字段的对象之外,子类也可以,如Inheritance中所述。

public class MountainBike extends Bicycle {
  public int seatHeight;
  constructor MountainBike(c,g,s,h) { /*...*/ }
  private static int mountainBikePrice = 324;
}

MountainBike现在有4个实例字段:cadencegearspeedseatHeight;和2个静态字段:numberOfBicyclesmountainBikePrice

我想在我的Javascript程序中模拟这种行为,但是,由于JS是面向原型而不是面向对象的,因此对象和子类无法访问他们的"类"成员。

// constructor
function Bicycle(c,g,s) {
  this.cadence = c
  this.gear = g
  this.speed = s
}
// instance methods
Bicycle.prototype.go = function () { /*...*/ }
Bicycle.prototype.stop = function () { /*...*/ }
// STATIC field
Bicycle.numberOfBicycles = 0 // <-- I want THIS field inherited

当我通过var myBike = new Bicycle()创建一个新的Bicycle对象时,我可以访问实例方法myBike.go()等,但我无法通过myBike.numberOfBicycles获取静态字段。 Java的。获得此功能的唯一方法是致电Bicycle.numberOfBicycles

此外,当我创建一个新的子类时,它无法访问其父类的字段。

// subclass constructor
function MountainBike(c,g,s,h) {
  Bicycle.call(this,c,g,s)
  this.seatHeight = h
}
// vvvvvvvv extension mechanism... ignore this vvvvvvvvvv
MountainBike.prototype = Object.create(Bicycle.prototype)
MountainBike.prototype.constructor = MountainBike
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
// STATIC field
MountainBike.mountainBikePrice = 324

如果我调用MountainBike.numberOfBicycles我得到undefined(这在Java中不会发生 - 它将返回父项的值。)

除了分配Bicycle.prototype.numberOfBicycles = 0之外,对象必须有一种更简单的方法来继承其类的属性,并且子类可以继承其父级的属性。

  1. 有没有办法访问对象的类,例如myBike.class?如果是,那么我可以致电myBike.class.numberOfBicycles
  2. 有没有办法访问子类的父类,如MountainBike.super

1 个答案:

答案 0 :(得分:1)

实际上,您要查找的属性为constructor(与myBike.constructor.numberOfBicycles中的属性一样)。

对象的构造函数(类似于)Java中的实例类。可能最好采取一些盐,因为这些概念不完全可以互换。

修改

所以我看到你基本上是在尝试使用原型和构造函数hacks在JavaScript中创建一些完整的“类”实现(这很好)。 Backbone在extend函数中有一个有趣的方法。相关来源如下(请参阅此代码许可的问题底部):

var extend = function(protoProps, staticProps) {
    var parent = this;
    var child;


    // Inherits constructor if not specified in child props.
    if (protoProps && _.has(protoProps, 'constructor')) {
        child = protoProps.constructor;
    } else {
        child = function(){ return parent.apply(this, arguments); };
    }

    // copy all properties from parent and from static properties
    // into child
    _.extend(child, parent, staticProps);

    // figure out child prototype (kind of like you had)
    child.prototype = Object.create(parent.prototype);
    _.extendOwn(child, protoProps);
    child.prototype.constructor = child;

    // Save super for later access (answers question 2)
    child.__super__ = parent.prototype;

    return child;
  };

注释是我的。我编辑了代码,以揭示OP发布的一些相似之处(即使用Object.create代替_.create)。使用它的方法是在父Parent.extend = extend;中设置,然后使用Child = Parent.extend({...new properties and methods...},...)创建子类。

我决定继续发布整个函数,因为它可能包含您尚未询问的问题的解决方案(例如构造函数的继承)。 特别针对问题2 ,Backbone开发人员决定使用__super__在子级中显式保存父类,因此您也可以在继承代码中执行此操作(在调用之后) Object.create)。

使用ES2015类和继承extends(这里是some good docs on it)可能更有意义。对它的支持不是很好,所以你需要使用预处理器,如Babel。以下是这些类的示例:

class Parent {...}

class Child extends Parent {...}

发布了Backbone代码片段的许可证:

  

(c)2010-2016 Jeremy Ashkenas,DocumentCloud和Investigative Reporters&amp;编辑。   Backbone可以在MIT许可下自由分发   所有细节和文件:
  http://backbonejs.org