1

次のコンストラクタがあるとします。

var Foo = function(){
   this.x = "y";
}

FooFoo.prototype.constructor同じ関数に評価されFoo.prototype.constructor = function(){this.x="z"}ますが、の結果は変わらないようですnew Foo()。ただし、結果は変わります

var i = new Foo();
i.constructor; // evals to function (){this.x = "z"}

何が起きてる?これを何かに使うつもりはありません。言語に興味があるだけです。

4

2 に答える 2

3

関数のプロパティconstructorprototypeプロパティは、関数を指すように意図されているため、オブジェクトにそれを構築したものを尋ねることができます。これは、関数オブジェクトの作成の一部として自動的に設定されます (仕様のセクション 13.2 を参照してください[またはより最新のバージョンについてはこちら])。それを変更しますが、デフォルトではそれが目的です。何年もの間、JavaScript 仕様は、プロパティがそこにあり、既定値が指定されていることだけを述べていました (つまり、既定値は.)。しかし、ES2015 以降ではそれが変更され、仕様のさまざまな操作で実際に次のようなプロパティが使用されるようになりました。constructorFoo.prototypeconstructorfunction Foo() { }Foo.prototype.constructorFooconstructorここここここ、そしてここ

(以下は ES2015 のclass機能が追加される前に書かれたものであることに注意してください。以下は、ES5 以前でこれを行う方法です。ES2015+ では、コンストラクター関数と継承階層を行っている場合、以下を行う正当な理由はありません。class[コンストラクター関数を使用して継承階層を構築しない場合 (その必要がない場合、JavaScript でそれらを行う方法は他にもあります — 以下のことを実行したり、 を使用したりclassすることはありません。])

継承に関連して、オーバーライドできるのには十分な理由があります。Base基本オブジェクトを作成するコンストラクターと、 の機能に加えて の追加/変更を加えたDerived派生オブジェクトを作成するコンストラクターが必要であるとします。通常の(私の考えでは理想的ではありませんが)完了したことを確認する方法(ヘルパースクリプトがない場合)は次のとおりです。BaseDerived

function Base() {
}
Base.prototype.foo = function() {
    console.log("I'm Base#foo");
};

function Derived() {
}
Derived.prototype = new Base(); // So we get all the `Base` stuff
Derived.prototype.bar = function() {
    console.log("I'm Derived#bar");
};

var d = new Derived();
d.foo(); // "I'm Base#foo"
d.bar(); // "I'm Derived#bar"

問題はd.constructor === BaseDerived. したがって、それを修正できることが重要です。

...
Derived.prototype = new Base();                           // So we get all the `Base` stuff
Object.defineProperty(Derived.prototype, "constructor", { // Fix up
    value: Derived,
    writable: true,
    configurable: true
});
...

(補足: このすべての配管 (およびスーパーコールに関する複雑さ) が、ES2015+ にclass構文がある理由です。)


上記は、継承階層を設定するための理想的な方法ではないことに注意してください。これは通常目にするものですが、上で述べたように、理想的ではありません。完全を期すために、ES5 構文に制限された環境では、これが優れています。

function Base() {
}
Base.prototype.foo = function() {
    console.log("I'm Base#foo");
};

function Derived() {
    Base.call(this); // So Base sets up its stuff
}
Derived.prototype = Object.create(Base.prototype); // So we get all the `Base` stuff
Object.defineProperty(Derived.prototype, "constructor", {
    value: Derived,
    writable: true,
    configurable: true
});
Derived.prototype.bar = function() {
    console.log("I'm Derived#bar");
};

var d = new Derived();
d.foo(); // "I'm Base#foo"
d.bar(); // "I'm Derived#bar" 

...ES5 以前の環境では、シム/ポリフィルを使用しますObject.create。しかし、繰り返しになりますが、これを直接行うことはありません (また、お勧めしません)。ヘルパー スクリプトを使用するので、宣言型で反復可能です。

于 2012-05-31T15:01:37.287 に答える
2

.prototype.constructor作成されたオブジェクトがコンストラクターを簡単に参照できるようにするためのヘルパープロパティです。this.constructorまたは、あなたの場合のようにi.constructor

任意に別のものに設定しても、次のオブジェクトのコンストラクターを取得することを期待するコード以外には何の効果もありませんobj.constructor

if( obj.constructor === Foo ) {
 //It's a Foo
}

したがって、そのままにしておくのは良い慣習です。

es5shim.constructor.prototypeshimに依存していますObject.getPrototypeOf

于 2012-05-31T15:01:50.060 に答える