在 PHP/Java 中可以做到:
class Sub extends Base
{
}
并且 Super 类的所有公共/受保护的方法、属性、字段等都会自动成为 Sub 类的一部分,如果需要,可以覆盖它们。
Javascript 中的等价物是什么?
在 PHP/Java 中可以做到:
class Sub extends Base
{
}
并且 Super 类的所有公共/受保护的方法、属性、字段等都会自动成为 Sub 类的一部分,如果需要,可以覆盖它们。
Javascript 中的等价物是什么?
在 JavaScript 中,您没有类,但您可以通过多种方式获得继承和行为重用:
伪经典继承(通过原型):
function Super () {
this.member1 = 'superMember1';
}
Super.prototype.member2 = 'superMember2';
function Sub() {
this.member3 = 'subMember3';
//...
}
Sub.prototype = new Super();
应与new
运算符一起使用:
var subInstance = new Sub();
函数应用程序或“构造函数链接”:
function Super () {
this.member1 = 'superMember1';
this.member2 = 'superMember2';
}
function Sub() {
Super.apply(this, arguments);
this.member3 = 'subMember3';
}
这种方法也应该与new
操作员一起使用:
var subInstance = new Sub();
与第一个例子的不同之处在于,当我们apply
将Super
构造函数添加到this
对象里面时Sub
,它会直接在新实例this
上添加分配给on的属性Super
,例如subInstance
包含属性member1
和member2
直接 ( 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;
}
这种方法基本上基于“对象增强”,您不需要使用new
运算符,并且如您所见,this
不涉及关键字。
var subInstance = createSub();
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';
上述方法是Crockford提出的原型继承技术。
对象实例继承自其他对象实例,仅此而已。
这种技术可以比简单的“对象增强”更好,因为继承属性不通过所有复制的新的对象的情况下,由于基体对象被设定为[[Prototype]]
所述的扩展的目的,在上面的例子中subInstance
物理上只包含member3
属性。
我现在改变了这样做的方式,我尽量避免使用构造函数及其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
使用 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
这是我 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"
在最新版本的 ECMAScript 标准(ES6) 中,您可以使用关键字class
。
请注意,类定义不是常规的object
;因此class成员之间没有逗号。要创建类的实例,您必须使用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'
要从基类继承,请使用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
在派生类中,您可以从任何构造函数或方法中使用 super 来访问其基类:
super().
super.getName()
。还有更多使用类。如果你想深入研究这个主题,我推荐Axel Rauschmayer 博士的“ ECMAScript 6 中的类”。*
好吧,在 JavaScript 中没有“类继承”,只有“原型继承”。因此,您不会创建“卡车”类,然后将其标记为“汽车”的子类。相反,您创建了一个对象“Jack”并说它使用“John”作为原型。如果约翰知道“4+4”是多少,那么杰克也知道。
我建议你在这里阅读 Douglas Crockford 关于原型继承的文章:http : //javascript.crockford.com/prototypal.html他还展示了如何让 JavaScript 像其他 OO 语言一样具有“相似”的继承,然后解释这一点实际上意味着以不打算使用的方式破坏 javaScript。
我觉得这句话最有启发性:
本质上,一个 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