1

より良いタイトルを知らなかったので、説明するために、「コンストラクター」があるとしましょう

  • オブジェクトをインスタンス化し、いくつかのプロパティを設定します
    • インスタンス化の過程で、別のオブジェクトが作成されます
    • この 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です

4

1 に答える 1

0

名前付き関数をプロパティ値として使用して、アトミック要素のインスタンスを共有します。

foo = {"1":1}
bar = {"1": function baz() { return foo["1"] } }

foo["1"] = 2;
foo["1"] === bar["1"]();

参考文献

于 2013-01-08T22:43:31.170 に答える