Javascript 如何从javascript中的类继承?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2107556/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-22 22:47:46  来源:igfitidea点击:

How to inherit from a class in javascript?

javascriptoop

提问by Click Upvote

In PHP/Java one can do:

在 PHP/Java 中可以做到:

class Sub extends Base
{
}

And automatically all public/protected methods, properties, fields, etc of the Super class become a part of the Sub class which can be overridden if necessary.

并且 Super 类的所有公共/受保护的方法、属性、字段等都会自动成为 Sub 类的一部分,如果需要,可以覆盖它们。

What's the equivalent for that in Javascript?

Javascript 中的等价物是什么?

采纳答案by Bjorn

I have changed how I do this now, I try to avoid using constructor functions and their prototypeproperty, but my old answer from 2010 is still at the bottom. I now prefer Object.create(). Object.createis available in all modern browsers.

我现在改变了这样做的方式,我尽量避免使用构造函数及其prototype属性,但我 2010 年的旧答案仍然在底部。我现在更喜欢Object.create(). Object.create可在所有现代浏览器中使用。

I should note that Object.createis usually much slowerthan using newwith a function constructor.

我应该注意到这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

jsfiddle

提琴手

One of the big benefits of using Object.create is being able to pass in a definePropertiesargument, which gives you significant control over how properties on the class can be accessed and enumerated over, and I also use functions to create instances, these serve as constructors in a way, as you can do initialization at the end instead of just returning the instance.

使用 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

jsfiddle

提琴手

This is my original answer from 2010:

这是我 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"

回答by CMS

In JavaScript you don't have classesbut you can get inheritance and behavior reuse in many ways:

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

Pseudo-classical inheritance (through prototyping):

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

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

function Sub() {
  this.member3 = 'subMember3';
  //...
}
Sub.prototype = new Super();

Should be used with the newoperator:

应与new操作员一起使用:

var subInstance = new Sub();

Function application or "constructor chaining":

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

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


function Sub() {
  Super.apply(this, arguments);
  this.member3 = 'subMember3';
}

This approach should also be used with the newoperator:

这种方法也应该与new操作员一起使用:

var subInstance = new Sub();

The difference with the first example is that when we applythe Superconstructor to the thisobject inside Sub, it adds the properties assigned to thison Super, directly on the new instance, e.g. subInstancecontains the properties member1and member2directly (subInstance.hasOwnProperty('member1') == true;).

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

In the first example, those properties are reached through the prototype chain, they exist on an internal [[Prototype]]object.

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

Parasitic inheritance or Power Constructors:

寄生继承或电源构造函数:

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

  return obj;
}

function createSub() {
  var obj = createSuper();
  obj.member3 = 'subMember3';
  return obj;
}

This approach is based basically on "object augmenting", you don't need to use the newoperator, and as you can see, the thiskeyword is not involved.

这种方法基本上基于“对象增强”,您不需要使用new运算符,并且如您所见,this不涉及关键字。

var subInstance = createSub();

ECMAScript 5th Ed. Object.createmethod:

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';

The above method is a prototypal inheritance technique proposed by Crockford.

上述方法是Crockford提出的一种原型继承技术。

Object instances inherit from other object instances, that's it.

对象实例继承自其他对象实例,仅此而已。

This technique can be better than simple "object augmentation" because the inherited properties aren't copied over all the new object instances, since the baseobject is set as the [[Prototype]]of the extendedobject, in the above example subInstancecontains physically only the member3property.

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

回答by Merlin

For those who reach this page in 2019 or after

对于那些在 2019 年或之后访问此页面的人

With the latest version of the ECMAScript standard (ES6), you can use the keyword class.

在最新版本的 ECMAScript 标准(ES6) 中,您可以使用关键字class

Note that the class definition is not a regular object; hence there are no commas between class members. To create an instance of a class, you must use the newkeyword. To inherit from a base class, use extends:

请注意,类定义不是常规的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'

To inherit from a base class, use extends:

要从基类继承,请使用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

From the derived class, you can use super from any constructor or method to access its base class:

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

  • To call the parent constructor, use super().
  • To call another member, use, for example, super.getName().
  • 要调用父构造函数,请使用 super().
  • 要呼叫其他成员,请使用例如super.getName()

There's more to using classes. If you want to dig deeper into the subject, I recommend “Classes in ECMAScript 6” by Dr. Axel Rauschmayer.*

还有更多使用类。如果你想深入研究这个主题,我推荐Axel Rauschmayer 博士的“ ECMAScript 6 中的类”。*

source

来源

回答by naivists

Well, in JavaScript there is no "class inheritance", there is just "prototype inheritance". So you don't make a class "truck" and then mark it as a subclass of "automobile". Instead, you make an object "Hyman" and say that it uses "John" as a prototype. If John knows, how much "4+4" is, then Hyman knows it, too.

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

I suggest you read Douglas Crockford's article about prototypal inheritance here: http://javascript.crockford.com/prototypal.htmlHe also shows how you can make JavaScript have "look-alike" inheritance as in other OO languages and then explains that this actually means breaking javaScript in a way it was not meant to be used.

我建议你在这里阅读 Douglas Crockford 关于原型继承的文章:http: //javascript.crockford.com/prototypal.html他还展示了如何让 JavaScript 像其他 OO 语言一样具有“相似”的继承,然后解释这一点实际上意味着以不打算使用的方式破坏 javaScript。

回答by Luke

I find this quote to be the most enlightening:

我觉得这句话最有启发性:

In essence, a JavaScript "class"is just a Function object that serves as a constructor plus an attached prototype object. (Source: Guru Katz)

本质上,一个 JavaScript 的“类”只是一个 Function 对象,它作为一个构造函数加上一个附加的原型对象。(来源:Guru Katz

I like using constructors rather than objects, so I'm partial to the "pseudo-classical inheritance" method described here by CMS. Here is an example of multiple inheritance with a prototype chain:

我喜欢使用构造函数而不是对象,所以我偏爱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

Here is another good resource from MDN, and here is a jsfiddle so you can try it out.

这是来自 MDN 的另一个很好的资源,这是一个 jsfiddle,因此您可以尝试一下

回答by Don Kirkby

Javascript inheritance is a bit different from Java and PHP, because it doesn't really have classes. Instead it has prototype objects that provide methods and member variables. You can chain those prototypes to provide object inheritance. The most common pattern I found when researching this question is described on the Mozilla Developer Network. I've updated their example to include a call to a superclass method and to show the log in an alert message:

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

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

Personally, I find inheritance in Javascript awkward, but this is the best version I've found.

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

回答by D.C.

you can't (in the classical sense). Javascript is a prototypical language. You will observe that you never declare a "class" in Javascript; you merely define the state and methods of an object. To produce inheritance, you take some object and prototype it. The prototype is extended with new functionality.

你不能(在古典意义上)。Javascript 是一种原型语言。你会发现你从来没有在 Javascript 中声明一个“类”;您只需定义对象的状态和方法。要产生继承,您需要获取一些对象并为其创建原型。原型扩展了新功能。

回答by nnattawat

function Person(attr){
  this.name = (attr && attr.name)? attr.name : undefined;
  this.birthYear = (attr && attr.birthYear)? attr.birthYear : undefined;

  this.printName = function(){
    console.log(this.name);
  }
  this.printBirthYear = function(){
    console.log(this.birthYear);
  }
  this.print = function(){
    console.log(this.name + '(' +this.birthYear+ ')');
  }
}

function PersonExt(attr){
  Person.call(this, attr);

  this.print = function(){
    console.log(this.name+ '-' + this.birthYear);
  }
  this.newPrint = function(){
    console.log('New method');
  }
}
PersonExt.prototype = new Person();

// Init object and call methods
var p = new Person({name: 'Mr. A', birthYear: 2007});
// Parent method
p.print() // Mr. A(2007)
p.printName() // Mr. A

var pExt = new PersonExt({name: 'Mr. A', birthYear: 2007});
// Overwriten method
pExt.print() // Mr. A-2007
// Extended method
pExt.newPrint() // New method
// Parent method
pExt.printName() // Mr. A

回答by chauwel

After reading many posts, i came up with this solution (jsfiddle here). Most of the time i don't need something more sophisticated

在阅读了许多帖子后,我想出了这个解决方案(这里是 jsfiddle)。大多数时候我不需要更复杂的东西

var Class = function(definition) {
    var base = definition.extend || null;
    var construct = definition.construct || definition.extend || function() {};

    var newClass = function() { 
        this._base_ = base;        
        construct.apply(this, arguments);
    }

    if (definition.name) 
        newClass._name_ = definition.name;

    if (definition.extend) {
        var f = function() {}       
        f.prototype = definition.extend.prototype;      
        newClass.prototype = new f();   
        newClass.prototype.constructor = newClass;
        newClass._extend_ = definition.extend;      
        newClass._base_ = definition.extend.prototype;         
    }

    if (definition.statics) 
        for (var n in definition.statics) newClass[n] = definition.statics[n];          

    if (definition.members) 
        for (var n in definition.members) newClass.prototype[n] = definition.members[n];    

    return newClass;
}


var Animal = Class({

    construct: function() {        
    },

    members: {

        speak: function() {
            console.log("nuf said");                        
        },

        isA: function() {        
            return "animal";           
        }        
    }
});


var Dog = Class({  extend: Animal,

    construct: function(name) {  
        this._base_();        
        this.name = name;
    },

    statics: {
        Home: "House",
        Food: "Meat",
        Speak: "Barks"
    },

    members: {
        name: "",

        speak: function() {
            console.log( "ouaf !");         
        },

        isA: function(advice) {
           return advice + " dog -> " + Dog._base_.isA.call(this);           
        }        
    }
});


var Yorkshire = Class({ extend: Dog,

    construct: function(name,gender) {
        this._base_(name);      
        this.gender = gender;
    },

    members: {
        speak: function() {
            console.log( "ouin !");           
        },

        isA: function(advice) {         
           return "yorkshire -> " + Yorkshire._base_.isA.call(this,advice);       
        }        
    }
});


var Bulldog = function() { return _class_ = Class({ extend: Dog,

    construct: function(name) {
        this._base_(name);      
    },

    members: {
        speak: function() {
            console.log( "OUAF !");           
        },

        isA: function(advice) {         
           return "bulldog -> " + _class_._base_.isA.call(this,advice);       
        }        
    }
})}();


var animal = new Animal("Maciste");
console.log(animal.isA());
animal.speak();

var dog = new Dog("Sultan");
console.log(dog.isA("good"));
dog.speak();

var yorkshire = new Yorkshire("Golgoth","Male");
console.log(yorkshire.isA("bad"));
yorkshire.speak();

var bulldog = new Bulldog("Mike");
console.log(bulldog.isA("nice"));
bulldog.speak();

回答by Adaptabi

You can use .inheritWithand .fastClasslibrary. It is faster than most popular libraries and sometimes even faster than the native version.

您可以使用.inheritWith.fastClass。它比大多数流行的库都要快,有时甚至比本机版本还要快。

Very easy to use:

非常容易使用:

function Super() {
   this.member1 = "superMember";//instance member
}.define({ //define methods on Super's prototype
   method1: function() { console.log('super'); } //prototype member
}.defineStatic({ //define static methods directly on Super function 
   staticMethod1: function() { console.log('static method on Super'); }
});

var Sub = Super.inheritWith(function(base, baseCtor) {
   return {
      constructor: function() {//the Sub constructor that will be returned to variable Sub
         this.member3 = 'subMember3'; //instance member on Sub
         baseCtor.apply(this, arguments);//call base construcor and passing all incoming arguments
      },
      method1: function() { 
         console.log('sub'); 
         base.method1.apply(this, arguments); //call the base class' method1 function
      }
}

Usage

用法

var s = new Sub();
s.method1(); //prints:
//sub 
//super