そのような例があります。
_function Rabbit() {
var jumps = "yes";
};
var rabbit = new Rabbit();
alert(rabbit.jumps); // undefined
alert(Rabbit.prototype.constructor); // outputs exactly the code of the function Rabbit();
_
_var jumps
_がパブリックになるように、Rabbit()
のコードを変更したい。私はこのようにします:
_Rabbit.prototype.constructor = function Rabbit() {
this.jumps = "no";
};
alert(Rabbit.prototype.constructor); // again outputs the code of function Rabbit() and with new this.jumps = "no";
var rabbit2 = new Rabbit(); // create new object with new constructor
alert(rabbit2.jumps); // but still outputs undefined
_
コンストラクター関数のコードをこの方法で変更できないのはなぜですか?
_prototype.constructor
_に再割り当てしてコンストラクターを変更することはできません
起こっているのは、_Rabbit.prototype.constructor
_が元のコンストラクター(function Rabbit(){...}
)へのポインターであるため、「クラス」のユーザーはインスタンスからコンストラクターを検出できます。したがって、実行しようとすると:
_Rabbit.prototype.constructor = function Rabbit() {
this.jumps = "no";
};
_
インスタンスからオブジェクトを動的にインスタンス化するために_prototype.constructor
_に依存するコードにのみ影響を与えます。
_new X
_を呼び出すと、JSエンジンは_X.prototype.constructor
_を参照せず、X
をコンストラクター関数として使用し、_X.prototype
_を新しく作成されたオブジェクトのプロトタイプとして使用します。 _X.prototype.constructor
_。
これを説明する良い方法は、new
演算子を自分で実装することです。 (Crockfordは幸せになり、新しいことはありません;)
_// `new` emulator
//
// Doesn't reference `.constructor` to show that prototype.constructor is not used
// when istantiating objects a la `new`
function make(ctorFun, argsArray) {
// New instance attached to the prototype but the constructor
// hasn't been called on it.
const newInstance = Object.create(ctorFun.prototype);
ctorFun.apply(newInstance, argsArray);
return newInstance;
}
// If you create a utility function to create from instance, then it uses the
// inherited `constructor` property and your change would affect that.
function makeFromInstance(instance, argsArray) {
return make(instance.constructor, argsArray);
}
function X(jumps) {
this.jumps = jumps;
}
// Flip the constructor, see what it affects
X.prototype.constructor = function(jumps) {
this.jumps = !jumps;
}
const xFromConstructorIsGood = make(X, [true]);
const xFromInstanceIsBad = makeFromInstance(xFromConstructorIsGood, [true]);
console.log({
xFromConstructorIsGood,
xFromInstanceIsBad
});
_
JSの継承
JS継承を支援するライブラリは、継承を実装し、次のような精神で_prototype.constructor
_に依存します。
_function extend(base, sub) {
function surrogateCtor() {}
// Copy the prototype from the base to setup inheritance
surrogateCtor.prototype = base.prototype;
sub.prototype = new surrogateCtor();
// The constructor property is set to the base constructor
// with the above trick, let's fix it
sub.prototype.constructor = sub;
}
_
上記のコードでは、コンストラクタープロパティをfixする必要があることがわかります。これは、インスタンスのみがある場合にオブジェクトのインスタンス化に使用されることがあるためです。しかし、実際のコンストラクターには影響しません。 JS継承に関する私の投稿を参照してください http://js-bits.blogspot.com/2010/08/javascript-inheritance-done-right.html
コンストラクタを再定義する方法コンストラクタを本当に再定義したい場合は、
_// If Rabbit had any custom properties on it
// (or static properties as some call it), they would not be copied, you'd have to do that manually using getOwnPropertyNames
// See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/getOwnPropertyNames
var oldProto = Rabbit.prototype;
Rabbit = function() {...};
Rabbit.prototype = oldProto;
_
これは、その参照を既にコピーしたコードには影響しないことに注意してください。たとえば:
_const myRefRabbit = Rabbit
_
これは、コンストラクター関数からではなく、リテラルからオブジェクトを作成する素晴らしい回避策です。
まず、コンストラクターの単なるローカル変数ではなく、jumps
メンバーをオブジェクトに含める場合は、this
キーワードが必要です。
function Rabbit() {
this.jumps = "yes";
};
var rabbit = new Rabbit();
alert(rabbit.jumps); // not undefined anymore
そして今、あなたは簡単にjumps
にあなたが望む方法で簡単にアクセスできます:
rabbit.jumps = 'no';
alert(rabbit.jumps); // outputs 'no'
しかし、別のRabbitオブジェクトを作成すると、コンストラクターで定義されたとおり、最初は「yes」になりますよね?
var rabbit2 = new Rabbit();
alert(rabbit.jumps); // outputs 'no' from before
alert(rabbit2.jumps); // outputs 'yes'
できることは、デフォルトのRabbitオブジェクトからRabbitを作成することです。具体的なウサギは、具体的なウサギオブジェクトの値を変更していない限り、オンザフライで変更しても、デフォルトのRabbitオブジェクトのデフォルト値を常に持ちます(実装)。これはおそらく最高の@Juan Mendesのソリューションとは異なりますが、別の観点を開くことができます。
Rabbit = {jumps : 'yes'}; // default object
rabbit = Object.create(Rabbit);
Rabbit.jumps = 'no';
rabbit2 = Object.create(Rabbit);
console.log(rabbit.jumps); // outputs "no" - from default object
console.log(rabbit2.jumps); // outputs "no" - from default object
// but...
rabbit.jumps = 'yes';
Rabbit.jumps = 'unknown';
console.log(rabbit.jumps); // outputs "yes" - from concrete object
console.log(rabbit2.jumps); // outputs "unknown" - from default object
以下をお試しください
function Rabbit() {
this.jumps = "no";
};
var rabbit = new Rabbit();
alert(rabbit.jumps); // Prints "no"