より良いタイトルを知らなかったので、説明するために、「コンストラクター」があるとしましょう
- オブジェクトをインスタンス化し、いくつかのプロパティを設定します
- インスタンス化の過程で、別のオブジェクトが作成されます
- この Objects プロトタイプは、最初の Object からその Children へのいくつかのプロパティをシャドウする必要があります
そのため、最初の Objects プロパティnum
が変更されたときに、他の Objects プロトタイプ プロパティnum
も変更する必要があります。
これはもちろん、次の場合に機能しますnum
。
- オブジェクトにラップ
- 非プリミティブ オブジェクトのプロパティ/要素
しかしnum
、数値または文字列の場合
num
プリミティブ変数が参照ではなく値として渡されるため、最初のオブジェクトで上書きされる場合、またはプロパティがオブジェクトであり、新しいオブジェクトで上書きされる場合、プロトタイプのプロパティは変更されません。
だから私の質問は、オブジェクトが別のオブジェクトからプロパティのプリミティブ値を継承し、それらに1つの参照を共有させることができる「きちんとした」方法はありますか?
ここにいくつかのコード例があります。最初のものはスキップできます。コードを完全にするためにここにあります
/* Inheritance Helper*/
var base = (function baseConstructor() {
var obj = {
create:function instantiation() {
if(this != base) {
var instance = Object.create(this.pub);
this.init.apply(instance,arguments);
this.instances.push(instance);
return instance;
} else {
throw new Error("You can't create instances of base");
}
},
inherit:function inheritation() {
var sub = Object.create(this);
sub.pub = Object.create(this.pub);
sub.sup = this;
return sub;
},
initclosure:function initiation() {},
instances: [],
pub: {}
};
Object.defineProperty(obj,"init",{
set:function (fn) {
if (typeof fn != "function")
throw new Error("init has to be a function");
if (!this.hasOwnProperty("initclosure"))
this.initclosure = fn;
},
get:function () {
var that = this;
//console.log(that)
return function() {
if(that.pub.isPrototypeOf(this)) //!(obj.isPrototypeOf(this) || that == this))
that.initclosure.apply(this,arguments);
else
throw new Error("init can't be called directly");
};
}
});
Object.defineProperty(obj,"create",{configurable:false,writable:false});
Object.defineProperty(obj,"inherit",{configurable:false,writable:false});
return obj;
})();
/*Helpers*/
function merge (obj) {
if(arguments.length < 2)
throw new Error({msg:"At least 2 parameters needed"});
for ( var i = 1, ilen = arguments.length;i < ilen; i++)
for (var k in arguments[i])
obj[k] = arguments[i][k];
}
/*Helpers for workarounds*/
function tieProp (prop,obj) {
if(arguments.length < 3)
throw new Error({msg:"At least 2 Objects are needed"});
var ref = obj[prop];
for ( var i = 1,ilen = arguments.length;i<ilen;i++)
Object.defineProperty(arguments[i],prop,{
set: function (val) {
ref = val;
},
get: function () {
return ref;
}
});
}
つまり、これはオブジェクトが作成される部分です
/*Example Code*/
var Series = base.inherit();
Series.init = function (specs) {
var _Series = this;
specs = specs ||{};
this.seasons = [];
var Season = Series.inherit();
Season.init = function(specs) {
var _Season = this;
specs = specs || {};
_Series.seasons.push(this);
merge(this,specs);
};
merge(this,specs);
Season.pub.score = this.score; // First way
Season.pub.stats = this.stats; // Second Way
tieProp("scoreTied",this,Season.pub); //Third Way
Season.pub.scoreSetter = this.scoreSetter; // Second Way
this.updateScore = function (score) { // Forth Way
this.scoreSetter = score;
Season.pub.scoreSetter = score;
};
tieProp("someObj",this,Season.pub); //Obj Example
this.addSeason = function (specs) {
Season.create(specs);
};
};
Series.pub.toString = function () {
return this.title + " has a score of " + this.scoreTied ;
};
var Futurama = Series.create({
title:"Futurama",
score:1, // 1.
scoreTied:2, // 2.
stats:{ //3.
score:3
},
scoreSetter:4,
someObj:{a:"b"}
});
Futurama.addSeason();
プロパティを変更する前に、コンソール出力をログに記録しましょう
console.log("BeforeChange",Futurama.score + " - " + Futurama.seasons[0].score); //"1 - 1"
console.log(Futurama.scoreTied + " - " + Futurama.seasons[0].scoreTied); // "2 - 2"
console.log(Futurama.stats.score + " - " + Futurama.seasons[0].stats.score); // "3 - 3"
console.log(Futurama.scoreSetter + " - " + Futurama.seasons[0].scoreSetter); //"4 - 4"
console.log(JSON.stringify(Futurama.someObj) + " - " + JSON.stringify(Futurama.seasons[0].someObj)); //"{"a":"b"} - {"a":"b"}"
次に、スコアのプロパティを変更しますFuturama
Futurama.score = 2; //TFirst way // This will fail
Futurama.scoreTied = 3; //Second way
Futurama.stats.score = 4; // Third way
Futurama.updateScore(5); // Forth Way
Futurama.someObj = {b:"a"}; // Object replacement
そしてそれらをログに記録します
console.log("After Change",Futurama.score + " - " + Futurama.seasons[0].score); // 2 - 1
console.log(Futurama.scoreTied + " - " + Futurama.seasons[0].scoreTied); // 3 - 3
console.log(Futurama.stats.score + " - " + Futurama.seasons[0].stats.score); //4 -4
console.log(Futurama.scoreSetter + " - " + Futurama.seasons[0].scoreSetter); //5 - 5
console.log(JSON.stringify(Futurama.someObj) + " - " + JSON.stringify(Futurama.seasons[0].someObj)) ; //"{"b":"a"} - {"b":"a"}"
したがって、これは次のいずれかを使用するときに可能になります
- プロパティに getter と setter を提供する Object.defineProperty
のように function tieProp (prop,obj) {...
しかし、Object.defineProperty を使用することがこの種の状況で適切かどうかはわかりません。プロパティ記述子を設定して、一部のプロパティがプリミティブ値への 1 つの参照を共有できるようにする必要がありますか?
- 参照として渡されるすべてのプリミティブ値をオブジェクトにラップし、このオブジェクト プロパティを変更します。
のようにSeason.pub.stats = this.stats; // Second Way
これは問題ありませんが、プロパティを別のプロパティに移動する必要があり、名前付けの自由度の一部が失われるため、私はこれに満足していません。この例ではscore
、Futurama のスコアとして希望しますではFuturama.score
なく中にいるFuturama.stats.score
*オブジェクトの両方の値を設定するプロパティのセッターを書く
*のように this.updateScore = function (score) { // Forth Way
*
しかし、オブジェクトにメソッドを追加する必要があるため、これは避けたいと思います
このようなことをまったく行うべきではないのか、それとも本当に簡単な方法を見逃しているのかわかりません??
正しい方向への提案や指摘は本当にありがたいです
回答とこれを読むための忍耐に事前に感謝します
これは、いじるJSBinです