0

I create an object, that I later am trying to use as a prototype. One of the properties of the object is an array. I create two objects using it as a prototype and push some elements into the array of the first one, why do they show up in the array of the second object and how do I fix that, thanks.

Please see the code:

var Category = {

          name: "",
         items: [],
    totalSpent: function(){
      var total = 0;
      this.items.forEach(function(item){
        sum += item.price;
      });
    }

  };

var cat1 = Object.create(Category);
var cat2 = Object.create(Category);

cat1.items.push("item1");

console.log(cat2.items);      //return ["item1"]
9
  • 1
    You're using the exact same object as the prototype of two different objects; why is the behavior surprising? The Object.create() call does not make a copy of the object passed into it. Commented Sep 25, 2014 at 23:36
  • 1
    Prototypical inheritance is about sharing functionality and not data. If you want to copy object contents around that's not Object.create (which creates an object with a given prototype) - that's Object.assign that copies data over (though that's ES6). Commented Sep 25, 2014 at 23:38
  • Pointy, i was thinking it will work same as an instantiating on object of a class would do. Commented Sep 25, 2014 at 23:45
  • possible duplicate of How do I assign an object to an array within another object? Commented Sep 25, 2014 at 23:46
  • 1
    that's why i said "when the class contains a list", as opposed to instances containing it. Commented Sep 26, 2014 at 1:05

2 Answers 2

1

Object.create does not make a deep copy of the object. It will return an object based on the second argument (or an empty object if second argument not given) with the first argument as it's prototype. If you then mutate members of that prototype it'll affect all instances that use that object as a prototype (in your case Category).

Both cat1 and cat2 have Category as it's prototype; so:

cat1.__proto__ === cat2.__proto__;//true
Category === cat1.__proto__;

To show you an example what you're doing without involving prototype (note: do not use proto, it's a non standard property):

var org = {member:22};
// copy is a reference to org
// same as cat1={};cat1.__proto__ = Category
// or cat1 = Object.create(Category)
var copy = org;
// same as cat1.items.push('item');
// you are mutating Category.items so mutating Category
copy.member=0;//mutating copy, so mutating org as well
console.log(org.member);//=0

With prototype involved things get a little more complicated as re assigning members would actually shadow that member instead of changing the prototype but the above example was for simplicity.

var proto = {member:22,other:{sub:22}};
var copy = Object.create(proto);
//this does not affect proto as it will shadow the member
copy.member=0;
//this will affect proto because you're mutating proto.other
copy.other.sub=0;

In your case the items member is instance specific and should not be defined on the prototype. To initialize instance specific members you can use constructor functions or an init function that initializes the instance before using it.

This, how prototype is used, shadowing and more is explained here.

Sign up to request clarification or add additional context in comments.

Comments

-1

Could you just try

var cat1 = new Category();
var cat2 = new Category();

instead of Object.create() to instantiate those objects?

more in depth explanation seen here: http://www.htmlgoodies.com/beyond/javascript/object.create-the-new-way-to-create-objects-in-javascript.html

1 Comment

Category is an object, and not a constructor function. This is wrong and will fail.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.