web-dev-qa-db-ja.com

Javascriptコンストラクタープロパティの重要性は何ですか?

Javascriptがオブジェクト指向を取り巻くように頭を曲げようとしていますが、他の多くの場合と同様に、constructorプロパティに関する混乱に直面しています。特に、constructorプロパティの重要性は、効果を持たせることができないようです。例えば。:

function Foo(age) {
    this.age = age;
}

function Bar() {
    Foo.call(this, 42);
    this.name = "baz"; 
}

Bar.prototype = Object.create(Foo.prototype); 
var b = new Bar;    

alert(b.constructor); // "Foo". That's OK because we inherit `Foo`'s prototype.
alert(b.name);        // "baz". Shows that Bar() was called as constructor.
alert(b.age);         // "42", inherited from `Foo`.

上記の例では、オブジェクトbには(Bar)と呼ばれる適切なコンストラクターがあり、Fooからageプロパティを継承しています。なぜ多くの人々がこれを必要なステップとして提案するのですか:

Bar.prototype.constructor = Bar;

明らかに、正しいBarコンストラクターwasbを構築するときに呼び出されるので、このプロトタイププロパティにはどのような影響がありますか?コンストラクタープロパティを「正しく」設定することで実際にどのような違いが生じるか知りたいのですが、オブジェクトが作成された後に実際に呼び出されるコンストラクターに影響を与えることがわかりません。

117
aaa90210

constructorプロパティは、内部的には実際的な違いはまったくありません。コードで明示的に使用している場合にのみ使用できます。たとえば、オブジェクトを作成した実際のコンストラクター関数への参照を各オブジェクトに必要とする場合があります。その場合は、例のように、コンストラクタ関数のconstructorプロパティにオブジェクトを割り当てることにより、継承をセットアップするときに、prototypeプロパティを明示的に設定する必要があります。

70
Tim Down

ステップ1は、constructorprototypeが何であるかを理解することです。難しいことではありませんが、古典的な意味での「継承」を手放さなければなりません。

コンストラクター

constructorプロパティしないは、プログラムで特定の効果を引き起こしますが、どの関数がnew演算子と組み合わせて使用​​されたかを確認することができます。オブジェクトを作成します。 new Bar()と入力するとBarになり、_new Foo_ itと入力するとFooになります。

プロトタイプ

prototypeプロパティは、問題のオブジェクトに要求されたプロパティがない場合のルックアップに使用されます。 _x.attr_と書くと、JavaScriptはattrの属性の中からxを見つけようとします。見つからない場合は、_x.__proto___を検索します。存在しない場合は、_x.__proto__.__proto___が定義されている限り、___proto___などを検索します。

それでは、___proto___とは何ですか?また、prototypeとは何の関係がありますか?端的に言えば、prototypeは「タイプ」用で、___proto___は「インスタンス」用です。 (型とインスタンスの間に実際には違いがないため、引用符で言います)。 x = new MyType()を記述すると、(とりわけ)起こることは_x.__proto____が_MyType.prototype_に設定されることです。

質問

さて、あなた自身の例が何を意味するのかを導き出すために必要なのは上記だけですが、実際の質問に答えてみてください。 「なぜ次のように書く」:

_Bar.prototype.constructor = Bar;_

私は個人的にそれを見たことがなく、少し馬鹿げていると思いますが、あなたがそれを与えた文脈では、_Bar.prototype_-オブジェクト(new Foo(42)を使用して作成された)が持っているようになりますBarではなくFooによって作成されます。タイプルックアップ(constructorプロパティ)が、より一般的なオブジェクトのタイプではなく、常に最も具体的なタイプを常に生成するC++/Java/C#のような言語に似たものを作成するものであると思いますプロトタイプチェーンに追加します。

私のアドバイス:JavaScriptの「継承」についてはあまり考えないでください。インターフェースとミックスインの概念はより理にかなっています。また、オブジェクトのタイプをチェックしないでください。代わりに、必要なプロパティを確認してください(「アヒルのように歩き、アヒルのように鳴くなら、それはアヒルです」)。

混乱を引き起こすのは、JavaScriptが上記のプロトタイプ機構だけである場合にJavaScriptを古典的な継承モデルに強制しようとすることです。 constructor- propertyを手動で設定することを提案した多くの人々は、おそらくそれをやろうとしました。抽象化は問題ありませんが、このコンストラクタープロパティの手動割り当ては、JavaScriptのあまり一般的な使用法ではありません。

98
Jakob

コンストラクターを使用する1つのケース:

  1. これは、継承の一般的な実現方法の1つです。

    _Function.prototype.extend = function(superClass,override) {
        var f = new Function();
        f.prototype = superClass.prototype;
        var p = this.prototype = new f();
        p.constructor = this;
        this.superclass = superClass.prototype;
        ...
    };
    _
  2. このnew f()はsuperClassのコンストラクターを呼び出さないため、subClassを作成するときに、次のように最初にsuperClassを呼び出す必要があります。

    _SubClass = function() {
        SubClass.superClass.constructor.call(this);
    };
    _

そのため、コンストラクタープロパティはここで意味があります。

10
Jack Hu

prototype.constructorプロパティがprototypeプロパティの再割り当てに耐えるようにするユースケースの1つは、prototypeで同じタイプの新しいインスタンスを生成するメソッドを定義する場合です。指定されたインスタンス。例:

function Car() { }
Car.prototype.orderOneLikeThis = function() {  // Clone producing function
    return new this.constructor();
}
Car.prototype.advertise = function () {
    console.log("I am a generic car.");
}

function BMW() { }
BMW.prototype = Object.create(Car.prototype);
BMW.prototype.constructor = BMW;              // Resetting the constructor property
BMW.prototype.advertise = function () {
    console.log("I am BMW with lots of uber features.");
}

var x5 = new BMW();

var myNewToy = x5.orderOneLikeThis();

myNewToy.advertise(); // => "I am BMW ..." if `BMW.prototype.constructor = BMW;` is not 
                      // commented; "I am a generic car." otherwise.
2
golem

コンストラクタープロパティは、オブジェクトインスタンスの作成に使用されたコンストラクターを指します。 「new Bar()」と入力すると「Bar」になり、「new Foo()」と入力すると「Foo」になります。

ただし、コンストラクタを設定せずにプロトタイプを設定すると、次のような結果が得られます。

function Foo(age) {
    this.age = age;
}

function Bar() {
    this.name = "baz"; 
}

Bar.prototype = new Foo(42); 
var one = new Bar();
console.log(one.constructor);   // 'Foo'
var two = new Foo();
console.log(two.constructor);   // 'Foo'

コンストラクターを実際にオブジェクトの作成に使用されたコンストラクターに設定するには、次のようにプロトタイプを設定する際にコンストラクターも設定する必要があります。

function Foo(age) {
    this.age = age;
}

function Bar() {
    this.name = "baz"; 
}

Bar.prototype = new Foo(42); 
Bar.prototype.constructor = Bar;
var one = new Bar();
console.log(one.constructor);   // 'Bar'
var two = new Foo();
console.log(two.constructor);   // 'Foo'
0
jsbisht