在PHP/Java的人可以做的:如何从JavaScript中的类继承?
class Sub extends Base
{
}
并自动所有的公共/保护方法,属性,字段,超类成为可以根据需要被重写的子类的一部分等。
Javascript中的等价物是什么?
在PHP/Java的人可以做的:如何从JavaScript中的类继承?
class Sub extends Base
{
}
并自动所有的公共/保护方法,属性,字段,超类成为可以根据需要被重写的子类的一部分等。
Javascript中的等价物是什么?
我已经改变了我现在的做法,我尽量避免使用构造函数和它们的属性,但我从2010年的旧回答仍然在底部。我现在更喜欢Object.create()
。 Object.create
适用于所有现代浏览器。
我应该注意到Object.create
通常是much slower比使用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"
你不能(在古典意义上的)。 Javascript是一种原型语言。你会发现你永远不会在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
构造函数在Sub
内的this
对象,它在Super
上直接在新实例上添加分配给this
的属性,例如,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 5th Ed。 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
属性。
不使用实例进行继承 - 使用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以获得解释的意见 – Christoph 2010-01-21 09:00:12
谢谢@Christoph,我正要提到'Object.create'方法:) – CMS 2010-01-21 15:18:45
这是不正确的继承,因为你将在Sub的原型上拥有Super的实例成员。 因此,所有Sub的实例将共享相同的'member1'变量,这根本不可取。当然,他们可以重写它,但这没有意义。 https://github.com/dotnetwise/Javascript-FastClass是一个更好的糖解决方案。 – Adaptabi 2014-04-18 07:52:02
那么,在JavaScript中没有“类继承”,只有“原型继承”。所以你不要制作“卡车”班,然后将其标记为“汽车”的一个子类。相反,你制作一个对象“杰克”,并说它使用“约翰”作为原型。如果约翰知道,“4 + 4”是多少,那么杰克也知道。
我建议你阅读道格拉斯克罗克福德有关原型继承的文章:http://javascript.crockford.com/prototypal.html他还展示了如何使JavaScript与其他OO语言具有“相似”的继承关系,并解释说这实际上意味着以某种方式打破javaScript并不意味着被使用。
我们假设杰克的原型是约翰。在运行期间,我向John添加了一个属性/行为。我会从杰克那里得到那些财产/行为吗? – 2015-05-07 02:41:44
你当然会。例如,这就是人们通常将“trim()”方法添加到所有字符串对象(它不是内置的)的方式。请参阅此处的示例:https://developer.mozilla.org/en-US/docs/Web/ JavaScript/Reference/Global_Objects/String/Trim – naivists 2015-05-07 06:02:35
您可以使用.inheritWith
和.fastClass
library。它比大多数流行的库更快,有时甚至比本地版本更快。
使用非常简单:
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
}
}
使用
var s = new Sub();
s.method1(); //prints:
//sub
//super
,我觉得这句话是最有启发性:
从本质上说,一个JavaScript “下课”只是一个Function对象,它服务于是一个构造函数加上一个附加的原型对象。(Source: Guru Katz)
我喜欢使用构造,而不是对象,所以我偏爱“伪经典的继承”方法described here by 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
这里是another good resource from MDN,这里是a jsfiddle so you can try it out。
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
在阅读了很多文章后,我想出了这个解决方案(jsfiddle here)。大多数时候我并不需要一些更复杂的
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();
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);
就个人而言,我觉得继承在Javascript尴尬,但这是我找到的最佳版本。
由于CMS的答案,并顺藤摸瓜与原型和的Object.create并没有什么过了一段时间,我能想出使用申请我的继承一个整洁的解决方案如下所示:
var myNamespace = myNamespace || (function() {
return {
BaseClass: function(){
this.someBaseProperty = "someBaseProperty";
this.someProperty = "BaseClass";
this.someFunc = null;
},
DerivedClass:function(someFunc){
myNamespace.BaseClass.apply(this, arguments);
this.someFunc = someFunc;
this.someProperty = "DerivedClass";
},
MoreDerivedClass:function(someFunc){
myNamespace.DerivedClass.apply(this, arguments);
this.someFunc = someFunc;
this.someProperty = "MoreDerivedClass";
}
};
})();
随着最新版本的ECMAScript标准(ES6)的达到这个页面,你可以使用去keywork extends
注意,CLAS s的定义不是经常的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'
从基类继承,使用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.getName()
。还有更多使用类。如果你想深入探究这个问题,我推荐Dr. Axel Rauschmayer的“Classes in ECMAScript 6”。*
在引擎盖下,'class'和'extends'是原型链的(超有用)语法糖:http://stackoverflow.com/a/23877420/895245 – 2016-11-20 12:21:06
只为你信息'instance.name'这里'mycar.name'将返回类的名字。这是ES6和ESnext的默认行为。这里为mycar.name将返回'车辆' – Shiljo 2017-08-08 13:16:38
从ES2015,这正是你如何在JavaScript
class Sub extends Base {
}
function Base() {
this.doSomething = function() {
}
}
function Sub() {
Base.call(this);
}
var sub = new Sub();
sub.doSomething();
请不要只发布代码,解释它做了什么以及它如何回答这个问题。 – 2017-06-28 11:40:51
链接做继承: http://www.crockford.com/javascript/inheritance.html或 http://phrogz.net/JS/Classes/OOPinJS2.html – 2010-01-21 07:32:20
看看这里:http://stackoverflow.com/questions/1908443/what-are-good-javascript-oop-resources – 2010-01-21 07:33:02
链接:http://ncombo.wordpress.com/2013/07/11/javascript-inheritance-done-right/ – Jon 2013-07-11 13:52:10