У PHP / Java можна зробити:
class Sub extends Base
{
}
І автоматично всі публічні / захищені методи, властивості, поля тощо класу Super стають частиною підкласу, який при необхідності може бути замінений.
Що еквівалент тому в Javascript?
У PHP / Java можна зробити:
class Sub extends Base
{
}
І автоматично всі публічні / захищені методи, властивості, поля тощо класу Super стають частиною підкласу, який при необхідності може бути замінений.
Що еквівалент тому в Javascript?
Відповіді:
Я змінив, як це роблю зараз, намагаюся уникати використання конструкторських функцій та їх 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"
alert()
щоб побачити, які instance.showColor()
прибутки я все-таки отримую undefined
. jsbin.com/uqalin/1
У 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
на 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';
Вищеописаний метод є прототиповою методикою успадкування, запропонованою Крокфордом .
Екземпляри об'єктів успадковують від інших екземплярів об'єкта, ось і все.
Цей метод може бути краще , ніж просто «об'єкт збільшення» , тому що спадкові властивості не копіюються всі нові екземпляри об'єктів, так як базова об'єкт встановлений як [[Prototype]]
частина розширеного об'єкта, в наведеному вище прикладі , subInstance
містить фізично тільки member3
властивість.
Object.create()
або власну clone()
функцію (наприклад, mercurial.intuxication.org/hg/js-hacks/raw-file/tip/clone.js ) для успадкування безпосередньо від об'єкта прототипу; дивіться коментарі до stackoverflow.com/questions/1404559/… для пояснення
Object.create
метод :)
member1
змінну, що зовсім не бажано. Звичайно, вони можуть це переписати, але це просто не має сенсу. github.com/dotnetwise/Javascript-FastClass - кращий цукровий розчин.
Sub.prototype = new Super();
. Що робити, якщо обидва класи ніколи не будуть використовуватися під час виконання сценарію? Це виглядає як питання про продуктивність. Чому мені потрібно створити батьківський клас, якщо дочірній клас насправді не використовується? Чи можете ви докладно уточнити? Ось проста демонстрація випуску: jsfiddle.net/slavafomin/ZeVL2 Дякую!
З останньою версією стандарту ECMAScript (ES6) ви можете використовувати ключове слово class
.
Зауважте, що визначення класу не є регулярним 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()
.Існує більше використання класів. Якщо ви хочете заглибитися в цю тему, я рекомендую « Класи в ECMAScript 6 » доктора Акселя Раушмаєра. *
class
і extends
це (ультра корисний) синтаксис для ланцюга прототипів: stackoverflow.com/a/23877420/895245
Ну, в JavaScript немає "спадкування класів", є просто "успадкування прототипу". Таким чином, ви не складаєте клас "вантажівка", а потім позначаєте його як підклас "автомобільний". Натомість ви робите об’єкт "Джек" і кажете, що він використовує "Джон" як прототип. Якщо Джон знає, скільки "4 + 4", значить і Джек.
Я пропоную вам прочитати статтю Дугласа Крокфорда про прототипічне успадкування тут: http://javascript.crockford.com/prototypal.html Він також показує, як ви можете зробити так, щоб JavaScript успадкував "схожий на" схожість, як і в інших мовах OO, а потім пояснює, що це насправді означає зламати javaScript таким чином, щоб його не передбачалося використовувати.
Я вважаю цю цитату найяскравішою:
По суті, JavaScript- клас "клас" - це лише функція "Функція", яка виконує функції конструктора плюс доданий об'єкт-прототип. ( Джерело: Гуру Кац )
Мені подобається використовувати конструктори, а не об'єкти, тому я частково ставлюся до методу "псевдокласичного успадкування", описаного тут 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
Ось ще один хороший ресурс від MDN , і ось jsfiddle, щоб ви могли його спробувати .
Успадкування 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);
Особисто я вважаю спадщину в Javascript незручною, але це найкраща версія, яку я знайшов.
ви не можете (у класичному розумінні). Javascript - це прототипічна мова. Ви помітите, що ви ніколи не оголошуєте "клас" у Javascript; ви просто визначаєте стан та методи об’єкта. Для отримання спадщини ви берете якийсь об'єкт і прототипуєте його. Прототип розширений з новою функціональністю.
Можна користуватися .inheritWith
і .fastClass
бібліотекою . Це швидше, ніж більшість популярних бібліотек, а іноді навіть швидше, ніж рідна версія.
Дуже простий у використанні:
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
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 ). Більшу частину часу мені не потрібно щось складніше
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();
Завдяки відповіді 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";
}
};
})();
З ES2015 саме так ви отримуєте спадщину в JavaScript
class Sub extends Base {
}
function Base() {
this.doSomething = function () {
}
}
function Sub() {
Base.call(this); // inherit Base's method(s) to this instance of Sub
}
var sub = new Sub();
sub.doSomething();
У Javascript немає класів. Заняття javascript - це лише синтаксична побудова цукру на вершині прототипічного успадкування шаблон що JavaScript. Ви можете використовувати JS class
для примусового успадкування прототипів, але важливо усвідомити, що ви фактично все ще використовуєте функції конструктора під кришкою.
Ці поняття також застосовуються, коли ви переходите з а es6
класу за допомогою ключового слова extends. Це просто створює додаткове посилання в ланцюзі прототипу. The__proto__
class Animal {
makeSound () {
console.log('animalSound');
}
}
class Dog extends Animal {
makeSound () {
console.log('Woof');
}
}
console.log(typeof Dog) // classes in JS are just constructor functions under the hood
const dog = new Dog();
console.log(dog.__proto__ === Dog.prototype);
// First link in the prototype chain is Dog.prototype
console.log(dog.__proto__.__proto__ === Animal.prototype);
// Second link in the prototype chain is Animal.prototype
// The extends keyword places Animal in the prototype chain
// Now Dog 'inherits' the makeSound property from Animal
Object.create()
- це також спосіб створити спадщину в JS в JavaScript. Object.create()
це функція, яка створює новий об'єкт, а приймає існуючий об'єкт як аргумент. Він призначить об'єкт, який був отриманий як аргумент__proto__
властивості новоствореного об'єкта. Знову важливо усвідомити, що ми пов'язані з прототипною парадигмою успадкування, яку втілює JS.
const Dog = {
fluffy: true,
bark: () => {
console.log('woof im a relatively cute dog or something else??');
}
};
const dog = Object.create(Dog);
dog.bark();
Ви не можете успадкувати клас у JavaScript, оскільки в JavaScript немає класів.