web-dev-qa-db-ja.com

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

ここで問題は、CのメソッドmodifyをAおよびBのメソッドでオーバーライドできる方法があるかどうかです。Javaではsuperキーワードを使用しますが、 JavaScriptでこのようなことをどのように達成できますか?

71
Daniel Nastase

編集:元の答えが書かれてから6年が経ち、多くが変わりました!

  • おそらく Babel などのツールでコンパイルされた新しいバージョンのJavaScriptを使用している場合、 se real classes を使用できます。
  • 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を実行するためのより良い構文を含む同様のライブラリを見てみてください。

125
Adam

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

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

38
Yotam Ofek

古典的なOOをエミュレートすることは避け、代わりにプロトタイプのOOを使用してください。プロトタイプのOO用のNiceユーティリティライブラリは 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);
6
Raynos

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

this.modify = function(){}

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

3
Alex Heyd

modify()をオーバーライドする場合、最後に呼び出したmodify()メソッドはグローバルコンテキストで呼び出されます。最初にAまたはBを継承する必要があります。

たぶんあなたはこれをやろうとしている:

この場合、CAを継承します

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

すべての変数を「公開」しない限り、つまり、直接または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の両方に個別に変更可能なメンバーxyが追加されました。これは、代わりに... = Cと書いた場合には当てはまりません。

次に、xy、およびmodifyはすべて「パブリック」メンバーであるため、異なるFunctionを割り当てる

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

その名前で元のFunctionを「オーバーライド」します。

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

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

HTH、

FK

1
FK82
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();
0
nghien_net 89