如何从javascript中的类继承?

Cli*_*ote 96 javascript oop

在PHP/Java中可以做到:

class Sub extends Base
{
}
Run Code Online (Sandbox Code Playgroud)

并且Super类的所有公共/受保护方法,属性,字段等自动成为Sub类的一部分,必要时可以覆盖它.

Javascript中的等价物是什么?

CMS*_*CMS 190

在JavaScript中,您没有类,但您可以通过多种方式获得继承和行为重用:

伪经典继承(通过原型设计):

function Super () {
  this.member1 = 'superMember1';
}
Super.prototype.member2 = 'superMember2';

function Sub() {
  this.member3 = 'subMember3';
  //...
}
Sub.prototype = new Super();
Run Code Online (Sandbox Code Playgroud)

应与new运营商一起使用:

var subInstance = new Sub();
Run Code Online (Sandbox Code Playgroud)

函数应用程序或"构造函数链接":

function Super () {
  this.member1 = 'superMember1';
  this.member2 = 'superMember2';
}


function Sub() {
  Super.apply(this, arguments);
  this.member3 = 'subMember3';
}
Run Code Online (Sandbox Code Playgroud)

这种方法也应该与new运营商一起使用:

var subInstance = new Sub();
Run Code Online (Sandbox Code Playgroud)

与第一个示例的不同之处在于,当我们applySuper构造函数添加到this对象内部时Sub,它会直接在新实例this上添加分配给on 的属性Super,例如subInstance包含属性member1member2直接(subInstance.hasOwnProperty('member1') == true;).

在第一个示例中,这些属性是通过原型链到达的,它们存在于内部[[Prototype]]对象上.

寄生继承或电源构造器:

function createSuper() {
  var obj = {
    member1: 'superMember1',
    member2: 'superMember2'
  };

  return obj;
}

function createSub() {
  var obj = createSuper();
  obj.member3 = 'subMember3';
  return obj;
}
Run Code Online (Sandbox Code Playgroud)

这种方法基本上基于"对象扩充",您不需要使用new运算符,如您所见,this不涉及关键字.

var subInstance = createSub();
Run Code Online (Sandbox Code Playgroud)

ECMAScript第5版.Object.create方法:

// Check if native implementation available
if (typeof Object.create !== 'function') {
  Object.create = function (o) {
    function F() {}  // empty constructor
    F.prototype = o; // set base object as prototype
    return new F();  // return empty object with right [[Prototype]]
  };
}

var superInstance = {
  member1: 'superMember1',
  member2: 'superMember2'
};

var subInstance = Object.create(superInstance);
subInstance.member3 = 'subMember3';
Run Code Online (Sandbox Code Playgroud)

上述方法是Crockford提出的原型继承技术.

对象实例继承自其他对象实例,就是这样.

这种技术可以比简单的"对象增强"更好,因为继承属性不通过所有的新对象实例复制,由于基座对象被设定为[[Prototype]]所述的扩展对象,在上述例子中subInstance包含物理上只有member3属性.

  • 不要使用实例进行继承 - 使用ES5`Object.create()`或自定义`clone()`函数(例如http://mercurial.intuxication.org/hg/js-hacks/raw-file/tip/ clone.js)直接从原型对象继承; 请参阅http://stackoverflow.com/questions/1404559/what-will-be-a-good-minimalistic-javascript-inheritance-method/1404697#1404697的评论,以获得解释 (3认同)

Bjo*_*orn 79

我现在已经改变了我的方法,我尽量避免使用构造函数及其prototype属性,但是我在2010年的旧答案仍然处于底层.我现在更喜欢Object.create(). Object.create适用于所有现代浏览器.

我应该注意,Object.create它通常比使用函数构造函数得多new.

//The prototype is just an object when you use `Object.create()`
var Base = {};

//This is how you create an instance:
var baseInstance = Object.create(Base);

//If you want to inherit from "Base":
var subInstance = Object.create(Object.create(Base));

//Detect if subInstance is an instance of Base:
console.log(Base.isPrototypeOf(subInstance)); //True
Run Code Online (Sandbox Code Playgroud)

的jsfiddle

使用Object.create的一大好处是能够传入一个defineProperties参数,它可以让您对如何访问和枚举类的属性进行重要控制,并且我还使用函数来创建实例,这些函数用作构造函数在某种程度上,因为你可以在最后进行初始化而不是只返回实例.

var Base = {};

function createBase() {
  return Object.create(Base, {
    doSomething: {
       value: function () {
         console.log("Doing something");
       },
    },
  });
}

var Sub = createBase();

function createSub() {
  return Object.create(Sub, {
    doSomethingElse: {
      value: function () {
        console.log("Doing something else");
      },
    },
  }); 
}

var subInstance = createSub();
subInstance.doSomething(); //Logs "Doing something"
subInstance.doSomethingElse(); //Logs "Doing something else"
console.log(Base.isPrototypeOf(subInstance)); //Logs "true"
console.log(Sub.isPrototypeOf(subInstance)); //Logs "true
Run Code Online (Sandbox Code Playgroud)

的jsfiddle

这是我2010年的原始答案:

function Base ( ) {
  this.color = "blue";
}

function Sub ( ) {

}
Sub.prototype = new Base( );
Sub.prototype.showColor = function ( ) {
 console.log( this.color );
}

var instance = new Sub ( );
instance.showColor( ); //"blue"
Run Code Online (Sandbox Code Playgroud)

  • sub.prototype.constructor值怎么样?我认为它应该设置为子值. (5认同)
  • @MONsDaR 那是因为它控制台日志,它不返回任何提示显示。你在 showColor 中看到 return 语句了吗? (2认同)

Mer*_*lin 46

适用于2015年或之后访问此页面的用户

使用最新版本的ECMAScript标准(ES6),您可以使用de keyworkclass

请注意,类定义不是常规的,object因此类成员之间没有逗号.要创建类的实例,必须使用new关键字.要从基类继承,请使用extends:

class Vehicle {
   constructor(name) {
      this.name = name;
      this.kind = 'vehicle';
   }
   getName() {
      return this.name;
   }   
}

// Create an instance
var myVehicle = new Vehicle('rocky');
myVehicle.getName(); // => 'rocky'
Run Code Online (Sandbox Code Playgroud)

要从基类继承,请使用extends:

class Car extends Vehicle {
   constructor(name) {
      super(name);
      this.kind = 'car'
   }
}

var myCar = new Car('bumpy');

myCar.getName(); // => 'bumpy'
myCar instanceof Car; // => true
myCar instanceof Vehicle; // => true
Run Code Online (Sandbox Code Playgroud)

从派生类中,您可以使用super从任何构造函数或方法访问其基类:

  • 要调用父构造函数,请使用 super().
  • 要呼叫其他成员,请使用,例如,super.getName().

使用类还有更多功能.如果你想深入研究这个主题,我推荐Axel Rauschmayer博士的" ECMAScript 6中的课程 ".*

资源


nai*_*sts 7

好吧,在JavaScript中没有"类继承",只有"原型继承".因此,您不要制作"卡车"类,然后将其标记为"汽车"的子类.相反,你创建一个对象"杰克"并说它使用"约翰"作为原型.如果约翰知道,"4 + 4"是多少,那么杰克也知道.

我建议你阅读道格拉斯克罗克福德关于原型继承的文章:http://javascript.crockford.com/prototypal.html他还展示了如何让JavaScript像其他OO语言一样具有"外观相似"的继承,然后解释这个实际上意味着以一种不打算使用的方式打破javaScript.


Luk*_*uke 6

我发现这句话是最具启发性的:

本质上,JavaScript "类"只是一个Function对象,用作构造函数和附加的原型对象.(来源:Guru Katz)

我喜欢使用构造函数而不是对象,所以我偏爱CMS所描述的"伪经典继承"方法.以下是使用原型链进行多重继承的示例:

// Lifeform "Class" (Constructor function, No prototype)
function Lifeform () {
    this.isLifeform = true;
}

// Animal "Class" (Constructor function + prototype for inheritance)
function Animal () {
    this.isAnimal = true;
}
Animal.prototype = new Lifeform();

// Mammal "Class" (Constructor function + prototype for inheritance)
function Mammal () {
    this.isMammal = true;
}
Mammal.prototype = new Animal();

// Cat "Class" (Constructor function + prototype for inheritance)
function Cat (species) {
    this.isCat = true;
    this.species = species
}
Cat.prototype = new Mammal();

// Make an instance object of the Cat "Class"
var tiger = new Cat("tiger");

console.log(tiger);
// The console outputs a Cat object with all the properties from all "classes"

console.log(tiger.isCat, tiger.isMammal, tiger.isAnimal, tiger.isLifeform);
// Outputs: true true true true

// You can see that all of these "is" properties are available in this object
// We can check to see which properties are really part of the instance object
console.log( "tiger hasOwnProperty: "
    ,tiger.hasOwnProperty("isLifeform") // false
    ,tiger.hasOwnProperty("isAnimal")   // false
    ,tiger.hasOwnProperty("isMammal")   // false
    ,tiger.hasOwnProperty("isCat")      // true
);

// New properties can be added to the prototypes of any
// of the "classes" above and they will be usable by the instance
Lifeform.prototype.A    = 1;
Animal.prototype.B      = 2;
Mammal.prototype.C      = 3;
Cat.prototype.D         = 4;

console.log(tiger.A, tiger.B, tiger.C, tiger.D);
// Console outputs: 1 2 3 4

// Look at the instance object again
console.log(tiger);
// You'll see it now has the "D" property
// The others are accessible but not visible (console issue?)
// In the Chrome console you should be able to drill down the __proto__ chain
// You can also look down the proto chain with Object.getPrototypeOf
// (Equivalent to tiger.__proto__)
console.log( Object.getPrototypeOf(tiger) );  // Mammal 
console.log( Object.getPrototypeOf(Object.getPrototypeOf(tiger)) ); // Animal
// Etc. to get to Lifeform
Run Code Online (Sandbox Code Playgroud)

这是来自MDN的另一个好资源,这里有一个jsfiddle所以你可以尝试一下.


Don*_*kby 5

Javascript 继承与 Java 和 PHP 有点不同,因为它实际上没有类。相反,它具有提供方法和成员变量的原型对象。您可以链接这些原型以提供对象继承。Mozilla 开发者网络上描述了我在研究这个问题时发现的最常见模式。我已经更新了他们的示例以包含对超类方法的调用并在警报消息中显示日志:

// Shape - superclass
function Shape() {
  this.x = 0;
  this.y = 0;
}

// superclass method
Shape.prototype.move = function(x, y) {
  this.x += x;
  this.y += y;
  log += 'Shape moved.\n';
};

// Rectangle - subclass
function Rectangle() {
  Shape.call(this); // call super constructor.
}

// subclass extends superclass
Rectangle.prototype = Object.create(Shape.prototype);
Rectangle.prototype.constructor = Rectangle;

// Override method
Rectangle.prototype.move = function(x, y) {
  Shape.prototype.move.call(this, x, y); // call superclass method
  log += 'Rectangle moved.\n';
}

var log = "";
var rect = new Rectangle();

log += ('Is rect an instance of Rectangle? ' + (rect instanceof Rectangle) + '\n'); // true
log += ('Is rect an instance of Shape? ' + (rect instanceof Shape) + '\n'); // true
rect.move(1, 1); // Outputs, 'Shape moved.'
alert(log);
Run Code Online (Sandbox Code Playgroud)

就我个人而言,我发现 Javascript 中的继承很尴尬,但这是我发现的最好的版本。