web-dev-qa-db-ja.com

Javascript:関数のプロトタイプを上書きする-悪い習慣?

関数を宣言すると、そのプロトタイプのコンストラクタープロパティが関数自体を指すようになるため、次のように関数のプロトタイプを上書きすることはお勧めできません。

function LolCat() {
}

// at this point LolCat.prototype.constructor === LolCat

LolCat.prototype = {
    hello: function () {
        alert('meow!');
    }
    // other method declarations go here as well
};

// But now LolCat.prototype.constructor no longer points to LolCat function itself

var cat = new LolCat();

cat.hello(); // alerts 'meow!', as expected

cat instanceof LolCat // returns true, as expected

これは私がそれを行う方法ではありません、私はまだ次のアプローチを好みます

LolCat.prototype.hello = function () { ... }

しかし、私は他の人がこれをしているのをよく見ます。

では、最初の例のように、便宜上、関数のプロトタイプオブジェクトを上書きして、プロトタイプからコンストラクター参照を削除することによる影響や欠点はありますか?

24
Vitaly

これに関する限り、ベストプラクティスについて言及している人は誰もいないので、constructorプロパティがこれまでに役立つことがわかるかどうかにかかっていると思います。

注目に値することの1つは、constructorプロパティは、破棄しない場合、作成されたオブジェクトでも使用できることです。それが役に立つかもしれないように私には思えます:

_var ClassOne = function() {alert("created one");}
var ClassTwo = function() {alert("created two");}

ClassOne.prototype.aProperty = "hello world"; // preserve constructor
ClassTwo.prototype = {aProperty: "hello world"}; // destroy constructor

var objectOne = new ClassOne(); // alerts "created one"
var objectTwo = new ClassTwo(); // alerts "created two"

objectOne.constructor(); // alerts "created one" again
objectTwo.constructor(); // creates and returns an empty object instance
_

ですから、それはアーキテクチャ上の決定であるように私には思えます。作成されたオブジェクトがインスタンス化された後、そのコンストラクターを再呼び出しできるようにしますか?もしそうならそれを保存します。そうでない場合は、それを破壊します。

ObjectTwoのコンストラクターは、標準のObjectコンストラクター関数とまったく同じになりました-役に立たないことに注意してください。

_objectTwo.constructor === Object; // true
_

したがって、new objectTwo.constructor()を呼び出すことはnew Object()と同等です。

21
Robin Winslow

それは悪い習慣ではありませんが、あなたは自分が何をしているのか、そしてその理由を知る必要があります。プロトタイプの継承に非常に役立ちます。プロトタイプを上書きするオブジェクトは、そのプロトタイプに割り当てたオブジェクトのすべてのプロパティを取得します。

を使用してオブジェクトを継承させます

ChildClassName.prototype = new ParentClass();.

これで、ChildClassNameにはParentClassのすべての機能がありますが、以前にプロトタイプに割り当てられていた機能はすべて失われます。を使用してオブジェクトのコンストラクタプロパティをリセットすることを忘れないでください。

ChildClassName.prototype.constructor=ChildClassName. 

それ以外の場合、オブジェクトは(オブジェクトのタイプをテストするときに)ChildClassNameタイプではなくParentClassタイプであると報告されます。

これで、自分で説明した方法で、ChildClassNameオブジェクトにメソッドを追加できます。

ChildClassName.prototype.myMethod = function(){
    //do stuff
}

その結果、親オブジェクト/「クラス」(もちろんJavaScriptには実際のクラスはありません)と、それを継承してその機能を拡張する子オブジェクト/「クラス」になります。

プロトタイプを上書きすると、割り当てられていたプロパティがすべて失われることを知っておく必要があります。継承オブジェクトを構築するとき、これはまさにあなたが望むものかもしれません。

5
Asciiom

この形:

LolCat.prototype = {
  hello: function () {
      alert('meow!');
  }
};

既存のメソッドとパブリックプロパティをすべて破棄します。例では、与えられたとおり、新しく作成されたLolCatにはプロパティやメソッドがないため、問題ではありません。ただし、より複雑なコードでは、これに注意する必要があります。

この形:

LolCat.prototype.hello = function () { ... }

既存のオブジェクトに新しいメソッドを追加し、既存のメソッドをそのまま保持します。

3

プロトタイプの継承を使用するときにconstructorを上書きすることは悪い習慣ではありません。実際、多くの人がそうしています:

LolCat.prototype = {
    constructor: LolCat,
    hello: function () {
        alert('meow!');
    }
};
1
jAndy

何年にもわたるJavaScriptの後で、オブジェクトの新しいインスタンスが、ミックスインで渡されたときにprototypeクラスが次のように宣言されたときに__proto__を失ったという奇妙なバグに遭遇しました。

MyClass.prototype = {
   constructor: MyClass,
   myMethod(){ ...}
};

使用するときにもう問題はありません:

Object.assign( MyClass.prototype, {
   myMethod(){ ...}
});

ボーナス:構成を再署名する必要はもうありません。

プロトタイププロパティを完全に上書きすると、その特殊属性もワイプして通常の属性に変換するためだと思います...おそらくこれはデフォルトで書き込み可能ではないはずです...

0
David

それは悪い習慣ではありません。しかし、以下のような関数をオーバーライドする簡単で標準的な方法があります。 '関数LolCat()'をグローバルに定義するときはいつでも、ウィンドウの下に作成されるので、いつでも以下のようにコーディングできます。

window.LolCat = function() {...};
LolCat.prototype.hello = function () { ... }
0
Somnath