Допустим, у вас есть следующий код:
function A() {
function modify() {
x = 300;
y = 400;
}
var c = new C();
}
function B() {
function modify(){
x = 3000;
y = 4000;
}
var c = new C();
}
C = function () {
var x = 10;
var y = 20;
function modify() {
x = 30;
y = 40;
};
modify();
alert("The sum is: " + (x+y));
}
Теперь вопрос в том, есть ли способ, которым я могу переопределить метод modify
из C
методов, которые находятся в A
и B
. В Java вы бы использовали super
-ключевое слово, но как добиться чего-то подобного в JavaScript?
javascript
oop
overriding
Даниэль Настасе
источник
источник
modify
это не метод, а вложенная функция - между этими двумя есть разница ...super
ключевое слово для доступа к частным полям и методам суперкласса. Вы не используете его для их отмены.Ответы:
Изменить: прошло шесть лет с тех пор, как был написан исходный ответ, и многое изменилось!
Удачи!
Наследование JavaScript немного отличается от Java. Вот как выглядит собственная объектная система JavaScript:
// Create a class function Vehicle(color){ this.color = color; } // Add an instance method Vehicle.prototype.go = function(){ return "Underway in " + this.color; } // Add a second class function Car(color){ this.color = color; } // And declare it is a subclass of the first Car.prototype = new Vehicle(); // Override the instance method Car.prototype.go = function(){ return Vehicle.prototype.go.call(this) + " car" } // Create some instances and see the overridden behavior. var v = new Vehicle("blue"); v.go() // "Underway in blue" var c = new Car("red"); c.go() // "Underway in red car"
К сожалению, это немного некрасиво и не включает в себя очень хороший способ «супер»: вам нужно вручную указать метод родительского класса, который вы хотите вызвать. В результате есть множество инструментов, которые делают создание классов удобнее. Попробуйте посмотреть Prototype.js, Backbone.js или аналогичную библиотеку, которая включает более удобный синтаксис для выполнения ООП в js.
источник
Так как это лучший хит в Google, я хотел бы дать обновленный ответ.
Использование классов ES6 значительно упрощает наследование и переопределение методов:
'use strict'; class A { speak() { console.log("I'm A"); } } class B extends A { speak() { super.speak(); console.log("I'm B"); } } var a = new A(); a.speak(); // Output: // I'm A var b = new B(); b.speak(); // Output: // I'm A // I'm B
super
Ключевое слово относится к родительскому классу при использовании в наследуемом классе. Кроме того, все методы родительского класса привязаны к экземпляру дочернего, поэтому вам не нужно писатьsuper.method.apply(this);
.Что касается совместимости: таблица совместимости с ES6 показывает только самые последние версии основных классов поддержки игроков (в основном). Браузеры V8 используют их с января этого года (Chrome и Opera), а Firefox, использующий движок SpiderMonkey JS, увидит классы в следующем месяце с официальным выпуском Firefox 45. Что касается мобильных устройств, Android по-прежнему не поддерживает эту функцию, а iOS 9, выпущенная пять месяцев назад, частично поддерживает.
К счастью, существует Babel , библиотека JS для повторной компиляции кода Harmony в код ES5. Классы и множество других интересных функций в ES6 могут сделать ваш код Javascript более читабельным и удобным в обслуживании.
источник
Once следует избегать эмуляции классического объектно-ориентированного программирования и использовать вместо этого прототипный объектно-ориентированный объект. Хорошая служебная библиотека для прототипных объектно-ориентированных приложений - это traits .
Вместо того, чтобы перезаписывать методы и настраивать цепочки наследования (всегда следует отдавать предпочтение композиции объектов, а не наследованию объектов), вы должны объединять повторно используемые функции в свойства и создавать объекты с ними.
Живой пример
var modifyA = { modify: function() { this.x = 300; this.y = 400; } }; var modifyB = { modify: function() { this.x = 3000; this.y = 4000; } }; C = function(trait) { var o = Object.create(Object.prototype, Trait(trait)); o.modify(); console.log("sum : " + (o.x + o.y)); return o; } //C(modifyA); C(modifyB);
источник
modify () в вашем примере - это частная функция, которая будет доступна только в пределах вашего определения A, B или C. Вам нужно будет объявить это как
this.modify = function(){}
C не имеет ссылки на своих родителей, если вы не передадите его C. Если C настроен для наследования от A или B, он унаследует свои общедоступные методы (а не свои частные функции, как вы определили modify ()). Когда C наследует методы от своего родителя, вы можете переопределить унаследованные методы.
источник
метод,
modify()
который вы вызвали в последнем, вызывается в глобальном контексте, если вы хотите переопределить,modify()
вы сначала должны наследоватьA
илиB
.Может, вы пытаетесь это сделать:
В этом случае
C
наследуетA
function A() { this.modify = function() { alert("in A"); } } function B() { this.modify = function() { alert("in B"); } } C = function() { this.modify = function() { alert("in C"); }; C.prototype.modify(); // you can call this method where you need to call modify of the parent class } C.prototype = new A();
источник
C.prototype.modify()
будет иметь неправильноеthis
значение. А именноC.prototype
вместо экземпляра c. Пожалуйста, используйте,.call(this)
но тогда ваш ответ будет просто дубликатом :)Нет, если вы не сделаете все переменные «общедоступными», т.е. сделаете их членами
Function
либо напрямую, либо черезprototype
свойство.var C = function( ) { this.x = 10 , this.y = 20 ; this.modify = function( ) { this.x = 30 , this.y = 40 ; console.log("(!) C >> " + (this.x + this.y) ) ; } ; } ; var A = function( ) { this.modify = function( ) { this.x = 300 , this.y = 400 ; console.log("(!) A >> " + (this.x + this.y) ) ; } ; } ; A.prototype = new C ; var B = function( ) { this.modify = function( ) { this.x = 3000 , this.y = 4000 ; console.log("(!) B >> " + (this.x + this.y) ) ; } ; } ; new C( ).modify( ) ; new A( ).modify( ) ; new B( ).modify( ) ;
Вы заметите несколько изменений.
Самое главное, что вызов предполагаемого конструктора «суперклассов» теперь неявный внутри этой строки:
<name>.prototype = new C ;
Как
A
иB
теперь будут иметь индивидуально изменяемые элементыx
иy
которые не были бы в случае , если бы мы написали... = C
вместо этого.Тогда
x
,y
иmodify
все «публичные» члены так , чтобы назначить другойFunction
к ним<name>.prototype.modify = function( ) { /* ... */ }
"переопределит" оригинал
Function
под этим именем.Наконец,
modify
нельзя выполнить вызов вFunction
объявлении, потому что неявный вызов «суперкласса» затем будет выполнен снова, когда мы установим предполагаемый «суперкласс» вprototype
свойство предполагаемых «подклассов».Но что ж, это более или менее похоже на то, как вы бы делали подобные вещи в JavaScript.
HTH,
FK
источник
<name>.prototype = new C;
любом случае, нетObjects
будет разделять один и тот же член,C
если вы не создаете экземплярC
объекта. Таким образом, изменениеx
вA
изменитсяx
наC
и, следовательно, изменитсяx
наB
. Что явно нежелательно.A
иB
наследоватьC
. Если бы эта строка отсутствовала, это было бы не так. Фактически, единственный прототип, к которому в этом случае будут иметь доступ оба,A
а такжеB
«тень»Object.prototype
.x
,y
и ,modify
и , таким образом , тень всехC
членов-х гг. Какой смысл использовать C в прототипе, если вы его не используете? Это мертвый код.function A() { var c = new C(); c.modify = function(){ c.x = 123; c.y = 333; } c.sum(); } function B() { var c = new C(); c.modify = function(){ c.x = 999; c.y = 333; } c.sum(); } C = function () { this.x = 10; this.y = 20; this.modify = function() { this.x = 30; this.y = 40; }; this.sum = function(){ this.modify(); console.log("The sum is: " + (this.x+this.y)); } } A(); B();
источник