質問

I'm working with a data object lit, then trying to create a new object that changes properties in the data property just for that instance, here's some test code from jsbin

data = {
  innerData : 1 
}

-------------

'This works :-)'

construct = function(d){
  this.data = Object.create(d);
};

construct.prototype.c = function(n){
  this.data.innerData  =  n;
};

construct.prototype.d = function(){
   console.log(this.data.innerData)
};

--------------

'This does not :-{'

construct = {
  data : Object.create(data),
  changeData : function(n){
    this.data.innerData  =  n;
  },
  showData:function(){
    console.log(this.data.innerData)
  }
}

--------------

newInst = Object.create(construct);
newInst.changeData(5);
newInst.showData();

newInst2 = Object.create(construct);
newInst2showData();

when I run it using the constructor/prototype functions it works and the console outputs 5,2

when I run it using the object literal the console outputs 5,5 I guess when I create the first instance it changes the actual data object and not the data property of the instance of the construct object.

If someone could explain in depth why this happens that would be much help as I've not been working with OOJS for that long

UPDATE:

so I had a little go at merging what I found useful from the answers and I've come up with this....

data = {
  innerData : 1 
}

function construct(d){
  return {
    data : Object.create(d),
    changeData : function(n){
      this.data.innerData  =  n;
    },
    showData : function(){
      console.log(this.data.innerData)
    }
  }
}

build = function(){
 return(new construct(data));
}

newInst = build();
newInst.changeData(5);
newInst.showData();

newInst2 = build();
newInst2.showData();
役に立ちましたか?

解決 2

In your second example, there is only ever one data object. That object lives inside construct and is available to all the subsequent objects on the prototype chain.

In your first example, you make a new data object every time a new instance is created. So each object gets its own copy of data.

Try this, for the first example:

console.log(newInst.data === newInst2.data); // should be false

and for the second example:

console.log(newInst.data === newInst2.data); // should be true

他のヒント

Given what we know about the inheritance, what does the following actually do

this.data.innerData  =  n;

where this is the result of Object.create(construct)?

  1. this does not have own property data, so look up in the inherited properties.
  2. Okay we found a data === Object.getPrototypeOf(this).data, call it d
  3. Next set innerData of d to n

So what the actual result has ended up is the innerData property has been set on the reference from the prototype, and not a new Object.

Why has this happened? Because if you have o = {} and try to do o.foo.bar, you get a TypeError: Cannot read property 'bar' of undefined, and therefore for it to not throw an error, it has to be accessing a defined Object.

var proto = {foo: {bar: 'fizz'}},
    obj = Object.create(proto);
obj.foo.bar = 'buzz';
proto.foo.bar; // "buzz" (i.e. NOT "fizz" anymore)
// and
obj.foo === Object.getPrototypeOf(obj).foo; // true

The second piece of code works just fine:

construct.changeData(2);
construct.showData(); // 2

The only difference is that in the above example construct is not a constructor, so there will be only a single instance of construct.data as opposed to the first approach; calling Object.create() on it will create a new object but will keep the same .data reference as the first.

This looks like an attempt to create a factory function instead of a constructor function. Since Object.create is now widespread, and shimmable for these purposes where not available, this has become perhaps the best default, although there are plenty of constructor functions still around.

Some of the other answers explain what went wrong with your attempt. Here's how you might do it so that it works as expected:

var factory = (function() {
  var clone = function(obj) {return JSON.parse(JSON.stringify(obj));};
  var data = {
    innerData : 1 
  };

  var proto = {
    changeData : function(n){
      this.data.innerData = n;
    },
    showData:function(){
      console.log(this.data.innerData)
    }
  };

  return function() {
    var obj = Object.create(proto);
    obj.data = clone(data);
    return obj;
  }
}());

But it looks as though your innerData might have been an experiment to try to get these things working. It it's not necessary, this would be cleaner:

var factory = (function() {
  var proto = {
    data: 1,
    changeData : function(n){
      this.data = n;
    },
    showData:function(){
      console.log(this.data)
    }
  };

  return function() {
    return Object.create(proto);
  }
}());
ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top