Методы переопределения JavaScript
Скажем, у вас есть код ниже:
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 с помощью методов, которые находятся в и B. В Java вы бы использовали ключевое слово super, но как вы можете добиться чего-то как это в JavaScript?
Ответы
Ответ 1
Изменить: теперь прошло шесть лет с момента написания оригинального ответа, и многое изменилось!
- Если вы используете более новую версию JavaScript, возможно, скомпилированную с помощью инструмента, такого как Babel, вы можете использовать реальные классы.
- Если вы используете конструкторы класса, представленные Angular или React, вы захотите посмотреть в документах для этой структуры.
- Если вы используете ES5 и делаете "поддельные" классы вручную, используя прототипы, нижеприведенный ответ все еще так же прав, как и когда-либо.
Удачи!
Наследование 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.
Ответ 2
Так как это лучший хит в 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-код более читабельным и поддерживаемым.
Ответ 3
Как-то следует избегать эмулирования классического ОО и вместо этого использовать прототипное ОО. Хорошая библиотека утилиты для прототипа OO 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);
Ответ 4
modify() в вашем примере - это закрытая функция, которая не будет доступна нигде, кроме определения A, B или C. Вам нужно объявить его как
this.modify = function(){}
C не имеет ссылки на своих родителей, если вы не передадите его C. Если C настроен на наследование от A или B, он наследует его общедоступные методы (а не его частные функции, как вы определили modify()). Когда C наследует методы от своего родителя, вы можете переопределить унаследованные методы.
Ответ 5
метод 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();
Ответ 6
Нет, если вы не сделаете все переменные "общедоступными", т.е. сделайте их членами 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.
НТН,
ФК
Ответ 7
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();