JavaScriptオーバーライドメソッド


87

以下のコードがあるとしましょう:

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であるメソッドを持つAB。Javaではsuper-keywordを使用しますが、JavaScriptでこのようなことをどのように実現できますか?


6
modifyはメソッドではなく入れ子関数です
...–ŠimeVidas2011

2
Javaでは、superキーワードを使用して、スーパークラスの非プライベートフィールドとメソッドにアクセスます。それらをオーバーライドするために使用することはありません。
fK82 2011

回答:


138

編集:元の回答が書かれてから6年が経ち、多くの変更が加えられました。

  • Babelなどのツールでコンパイルされた新しいバージョンのJavaScriptを使用している場合は、実際のクラス使用できます
  • 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でOOPを実行するためのより優れた構文を含む同様のライブラリを調べてみてください。


2
ツールを使用して「クラスの作成をより適切にする」代わりに、クラスを作成することはできませんでした。jsでの従来のOOエミュレーションは、常に厄介になります。
Raynos 2011

1
(建設的なコメントではありません)ブラウザの世界で「低レベル」言語であるということは、理由もなく非常に醜いです。まだそれを学んでいます、ありがとう!
dnuske 2012年

9
Car.prototype = new Vehicle();の代わりに私は信じています。これはCar.prototype = Object.create(Vehicle.prototype);である必要があります。番号?
ジョーダン

@Martinは右、参照されるjavascriptの継承
matoni

Car.prototype = new Vehicle();の理由の1つ。色を受け取っている間、Vehicle()に渡すものがないため、は正しくありません。
Tushar Arora 2016

63

これはグーグルのトップヒットなので、私は更新された答えを与えたいと思います。

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ブラウザは今年の1月からそれらを持っており(ChromeとOpera)、FirefoxはSpiderMonkey JSエンジンを使用して、公式のFirefox45リリースで来月クラスを見る予定です。モバイル側では、Androidはまだこの機能をサポートしていませんが、5か月前にリリースされたiOS9は部分的にサポートしています。

幸い、HarmonyコードをES5コードに再コンパイルするためのJSライブラリであるBabelがあります。クラス、およびES6の他の多くの優れた機能により、Javascriptコードをより読みやすく保守しやすくすることができます。


10
この答えはより多くの信用に値し、現在正しい答えです。
Klompenrunner 2018

6

かつては、従来のOOのエミュレートを避け、代わりにプロトタイプのOOを使用する必要があります。プロトタイプOOの優れたユーティリティライブラリは特性です。

メソッドを上書きして継承チェーンを設定するのではなく(オブジェクト継承よりもオブジェクトコンポジションを優先する必要があります)、再利用可能な関数をトレイトにバンドルし、それらを使用してオブジェクトを作成する必要があります。

実例

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);

10
あなたは質問に答えていません。どちらかといえばコメントです。
fK82 2011

FK82 @私たちは聞かせてチャットでこの議論を続ける
レイノス

3

あなたの例のmodify()はプライベート関数であり、A、B、またはC定義内以外の場所からはアクセスできません。あなたはそれを次のように宣言する必要があります

this.modify = function(){}

Cに渡さない限り、Cはその親を参照しません。CがAまたはBから継承するように設定されている場合、Cはパブリックメソッドを継承します(modify()を定義したようなプライベート関数ではありません)。Cが親からメソッドを継承すると、継承されたメソッドをオーバーライドできます。


modifyはローカル関数です。javascriptにはプライベートはありません
Raynos 2011

ローカル/プライベート、それは同じことではなく、単に異なる用語ですか?
Alex Heyd 2011

2

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();

1
C.prototype.modify()間違ったthis値になります。つまりC.prototype、cのインスタンスの代わりに。使用してください、.call(this)しかしあなたの答えはただの重複です:)
Raynos 2011

1

すべての変数を「パブリック」にしない限り、つまり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 ;

どちらAB今持っているだろう、個別に変更可能なメンバーをxしてyいるが、我々が書かれているかどうケースではないでしょう... = C代わりに。

その後、xyおよびmodifyすべての「パブリック」メンバーであるので、別のを割り当てることFunction、それらに

 <name>.prototype.modify = function( ) { /* ... */ }

Functionその名前でオリジナルを「上書き」します。

最後に、想定される「スーパークラス」を想定される「サブクラス」のプロパティに設定すると、「スーパークラス」への暗黙的な呼び出しが再度実行されるためmodifyFunction宣言での呼び出しを行うことはできませんprototype

しかし、まあ、これは多かれ少なかれ、JavaScriptでこの種のことを行う方法です。

HTH、

FK


<name>.prototype = new C;とにかく、プロトタイプのすべてのメンバーをシャドウイングすることに意味はありません
Raynos 2011

@Raynos:はい、あります。つまり、オブジェクトをインスタンス化しない場合、すべての継承Objectsは同じメンバーを共有することになりCますC。したがって、に変更xするAと、に変更さxC、したがってに変更さxBます。これは明らかに望ましくありません。
fK82 2011

あなたは要点を逃した。行を削除しても、コードは引き続き機能します
Raynos 2011

@Raynos:あなたは私が恐れているあなた自身のポイントを逃しています。;-)我々はしたいAB継承しますC。その行が欠落している場合は、そうではありません。実際、その場合、「シャドウ」AだけでなくB「シャドウ」もアクセスできる唯一のプロトタイプはですObject.prototype
fK82 2011

コードを見てください。AとBは、プロトタイプのCのメンバーを使用しません。したがって、Cからの「継承」は役に立ちません。AとB再定義するためであるxymodifyとは、このように全ての影Cのメンバーを。Cを使用しない場合、プロトタイプにCを入れる意味は何ですか?デッドコードです。
Raynos 2011

0

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();

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.