Как наследовать от класса в JavaScript?
в PHP / Java можно сделать:
class Sub extends Base
{
}
и автоматически все открытые / защищенные методы, свойства, поля и т. д. суперкласса становятся частью подкласса, который при необходимости может быть переопределен.
что эквивалентно этому в Javascript?
15 ответов:
Я изменил, как я делаю это сейчас, я стараюсь избегать использования функций конструктора и их
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одно из больших преимуществ использования объекта.создать будучи в состоянии пройти в 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 у вас нет классы но вы можете получить наследование и повторное использование поведения во многих отношениях:
Псевдоклассическое наследование (через прототипирование):
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();разница с первым примером заключается в том, что когда мы
applytheSuperконструкторthisобъект внутриSub, он добавляет свойства, назначенныеthisonSuper, непосредственно на новом экземпляре, например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]]на extended
для тех, кто достигнет этой странице в 2015 году или после
С последней версией стандарта ECMAScript (ES6), вы можете использовать de keywork
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'наследовать от базового класса, используйте
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().там больше к использованию классов. Если вы хотите копнуть глубже в эту тему, рекомендую "классы в ECMAScript 6 " доктор Аксель Rauschmayer.*
Ну, в 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 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 неудобным, но это лучшая версия, которую я нашел.
вы не можете (в классическом смысле). 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 и после возиться некоторое время с прототипом и объектом.создайте, а что нет, я смог придумать аккуратное решение для моего наследования, используя apply, как показано здесь:
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"; } }; })();
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();
на ES6 классы:
Javascript не имеет классов. Классы в javascript - это просто синтаксический сахар, построенный поверх прототипного наследования шаблон, что javascript. Вы можете использовать JS
classдля реализации прототипного наследования, но важно понимать, что вы на самом деле еще используют функции конструктора под капотом.эти понятия также применяются, когда вы расширяетесь от '' С помощью ключевого слова extends. Это только создает дополнительное звено в цепочке прототипов. Элемент
__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
Comments