1

私は JavaScript に非常に慣れておらず、C++/Java のバックグラウンドを持っているため、「古典的な」言語に慣れています。

クラスがないので、JavaScriptで次をどのように実装しますか!?

たとえば、派生クラス B および C が実装する必要があるいくつかの関数を定義する基本クラス A があるとします (Java っぽい疑似コード)。

public class A {
  public void doSomething();
  public void doSomethingElse();
};

public class B extends A {
  public void doSomething() { 
    // does B sort of something 
  };

  public void doSomethingElse() { 
    // does B sort of something else };
  };
};

public class C extends A {
  public void doSomething() { 
    // does C sort of something 
  };

  public void doSomethingElse() { 
    // does C sort of something else };
  };
};

次に、B または C を作成して、A で定義されたすべての関数が含まれていることを知りながら、それを操作したいと考えています。

例えば

A a = new B();
b.doSomething();

JSでプログラミングするときにこれがどのように考えるべきかさえわかりませんか?Douglas Crockfords の Web ページをいくつか読みましたが、まだ混乱しています!!!.

4

3 に答える 3

2
function A() {

};

A.prototype.doSomething = function() {
    console.log("hi")
}

A.prototype.doSomethingElse = function() {}

function B() { 
   A.apply(this,arguments) ) 
};

function C() { 
   A.apply(this,arguments) ) 
};

B.prototype = Object.create(A.prototype);
C.prototype = Object.create(A.prototype);

var b = new B();
var c = new C();

b.doSomething();
c.doSomethingElse();

関数のプロトタイプ チェーンにそれらのオブジェクトを設定することにより、他のオブジェクトから継承できます。

これらの基本関数をオーバーライドしたい場合があるため、次のように行うことができます

B.prototype.doSomething = function() {
   console.log("goodbye");
}

次に、型 b のオブジェクトは、doSomething を呼び出すと、hello ではなくさよならを言います。c は同じままです。

これは、 http://jsfiddle.net/Yp3UR/を試すために試すことができるフィドルです。

これに関する優れた外部リソースがいくつかの場所にあります

StackOverflow で見ることができます

于 2013-06-11T14:56:54.330 に答える
1

考え方: Javascript や同様の言語では、各オブジェクトには、それ自体がオブジェクトでもあるプロトタイプがあります。オブジェクトのメソッドまたはプロパティにアクセスしようとすると (JavaScript では関数はファースト クラスであるため、メソッドとプロパティの区別は誤解を招きやすいため)、インタープリターがオブジェクト自体を見つけられない場合は、プロトタイプを調べます。プロトタイプもオブジェクトであるため、独自のプロトタイプ (オブジェクト プロトタイプ プロトタイプ) も持ちます。したがって、この一連のプロトタイプがあり、継承の各レベルに 1 つずつ、基本クラスの Object までトレースします。その時点で、アクセスしようとしていたプロパティが見つからない場合、インタープリターは未定義のプロパティ エラーをスローします。

実装方法: 継承を行う方法は多数あります。これは私が使用するもので、必ずしも最適なものではありませんが、最も理解しやすいものです。

//A constructor
var A= function() {};

A.prototype.doSomething= function() { };

A.prototype.doSomethingElse= function() { };

//B constructor
var B= function () {
   A.apply(this, arguments); //calls A constructor on this instance of B
};

B.prototype= new A(); //this makes B "extend" A. Basically it sets B prototype to be an instance of A.

B.prototype.doSomething= function() {
   A.doSomething.apply(this, arguments); //calling "super"
};

B.prototype.doSomethingElse= function() {
   A.doSomethingElse.apply(this, arguments); //calling "super"
};



//C constructor
var C= function () {
   A.apply(this, arguments);
};

C.prototype= new A();

C.prototype.doSomething= function() {
   A.doSomething.apply(this, arguments); //calling "super"
};

C.prototype.doSomethingElse= function() {
   A.doSomethingElse.apply(this, arguments); //calling "super"
};

したがって、Cにメソッド doSomethingElseがなく、次のようにするとします。

c= new C();
c.doSomethingElse();

c インスタンスで A.doSomethingElse メソッドを呼び出します。

.apply 関数の簡単な説明: javascript の関数はオブジェクトを「拡張」します。そのため、それらはオブジェクトそのものです。実際、これを実際に行うことができます:

var myFunc= new Function("alert('myFunc');");
myFunc();

関数はオブジェクトであるため、独自のプロパティとメソッドもあります。「申し込む」もその一つです。

あなたがこれを言うとき:

//A constructor
var A= function() {};

A.prototype.doSomething= function() { };

実際に関数を作成して A に格納し、次に A プロトタイプ内にメソッドを配置します (関数はオブジェクトであるため、プロトタイプがあることを思い出してください)。これを行う場合:

var a= new A(arg1,arg2,arg3...);

A のインスタンスを作成しています。「new」演算子は、基本的にこれを行う特別な種類の演算子です。

a= A.apply(a, [arg1,arg2,arg3,...]);
a.prototype= A.prototype;

Function.apply メソッドの説明は次のとおりです: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/apply?redirectlocale=en-US&redirectslug=JavaScript%2FReference%2FGlobal_Objects %2F関数%2F適用

そして、ここに渡される「引数」配列の説明があります: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions_and_function_scope/arguments

あなたがこれを言うとき:

C.prototype.doSomething= function() {
   A.doSomething.apply(this, arguments);
};

この場合の A.doSomething は Java の静的関数に似ていることに注意してください。A のインスタンスのメソッドを呼び出しているのではなく、実際にはコンストラクター関数 A に存在するメソッドを呼び出しています (メソッドは実際には A.プロトタイプですが、関数はオブジェクトであるため、インタープリターはプロトタイプでそれ自体を探します)。

コンストラクターは関数であり、関数はオブジェクトであり、オブジェクトにはプロトタイプがあり、プロトタイプはオブジェクトであり、オブジェクトはその内部に関数を持つことができるため、これをすべて行うことができます。クレイジーでしょ?しかし、先に説明したプロトタイプ チェーンについて考えるのをやめれば、それほど難しいことではありません。その文を数回読み直してください。

なぜこのすべてのナンセンスなのですか? あなたはおそらく今少し混乱しているので、ネットでもっと例を探すことをお勧めします。しかし、これは複雑で過度に複雑であると言うのは簡単です。(javascript では) 複雑ですが、非常に強力でもあります。実行時にオブジェクトの動作を変更できます。

実行時の任意の時点でこの小さなコードを実行すると

A.prototype.doSomething= function() {
    A.doSomethingElse.(apply(this, arguments));
}

実際には、A のすべてのインスタンスと、それを継承する他のクラスの動作を変更しています (B と C のすべてのインスタンスも変更されます)。この場合、A.doSomething は A.doSomethingElse とまったく同じように動作します。クレイジーなコードを一切使わずに Java リフレクションを考えてみてください。

実際、String や Array などの Javascript の組み込みクラスの動作を変更できます。プログラムのどこかでこのコードを実行すると、次のようになります。

String.prototype.alert= function() {
   alert(this);
}

次のことができるようになりました。ポップアップ ボックスが表示され、その中に「テキスト」が表示されます。ただし、組み込みクラスをそのように変更しないでください。これは悪い習慣です。

これは、プロトタイプ ベースのオブジェクト指向を使用することの多数の利点の 1 つにすぎません。他にもたくさんあります。

プライベートメソッドはどうですか? これらは JavaScript には存在しませんが、クロージャーを介して別の関数からのみ見える関数を作成できます。プライベート メソッドを作成する必要がある場合は、クロージャについて読むことをお勧めします。

于 2013-06-11T16:58:57.670 に答える