Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Javascript object members that are prototyped as arrays become shared by all class instances

Tags:

Has anyone noticed this behavior before? This really threw me off... I would have expected prototyped arrays to be private to each class instance rather than shared between all class instances.

Can someone verify that this is the correct behavior and perhaps explain this behavior in more detail?

Notice the commented code and how it affects the behavior of the script.

<html> <head>  <script type="text/javascript">  function print_r( title, object ) {      var output = '';     for( var key in object ) {          output += key + ": " + object[ key ] + "\n";      }      output = title + "\n\n" + output;      alert( output );  }  function Sandwich() {      // Uncomment this to fix the problem     //this.ingredients = [];  }  Sandwich.prototype = {      "ingredients" : [],     "addIngredients" : function( ingArray ) {          for( var key in ingArray ) {              this.addIngredient( ingArray[ key ] );          }      },     "addIngredient" : function( thing ) {          this.ingredients.push( thing );      }  }  var cheeseburger = new Sandwich(); cheeseburger.addIngredients( [ "burger", "cheese" ] );  var blt = new Sandwich(); blt.addIngredients( [ "bacon", "lettuce", "tomato" ] );  var spicy_chicken_sandwich = new Sandwich(); spicy_chicken_sandwich.addIngredients( [ "spicy chicken pattie", "lettuce", "tomato", "honey dijon mayo", "love" ] );  var onLoad = function() {      print_r( "Cheeseburger contains:", cheeseburger.ingredients );  };  </script>  </head> <body onload="onLoad();"> </body> </html> 

Many thanks.

like image 459
Dan Avatar asked Dec 13 '10 02:12

Dan


People also ask

Are objects and arrays the same in JavaScript?

Both objects and arrays are considered “special” in JavaScript. Objects represent a special data type that is mutable and can be used to store a collection of data (rather than just a single value). Arrays are a special type of variable that is also mutable and can also be used to store a list of values.

Can JavaScript objects hold arrays?

The Array object lets you store multiple values in a single variable. It stores a fixed-size sequential collection of elements of the same type.

How does JavaScript inheritance work?

When it comes to inheritance, JavaScript only has one construct: objects. Each object has a private property which holds a link to another object called its prototype. That prototype object has a prototype of its own, and so on until an object is reached with null as its prototype.

What is prototype chaining in JavaScript?

That means all the objects in JavaScript, inherit the properties and methods from Object. prototype. This is called Prototype chaining. This is a very powerful and potentially dangerous mechanism to override or extend object behavior. Objects created using new keyword, inherit from a prototype called Object.


2 Answers

The prototype of an object is just an object. The prototype properties are shared between all objects that inherit from that object. No copies of the properties are made if you create a new instance of a "class" (classes don't exist anyway in JS), i.e. an object which inherits from the prototype.

It only makes a difference on how you use the these inherited properties:

function Foo() {}  Foo.prototype = {     array: [],     func: function() {} }  a = new Foo(); b = new Foo();  a.array.push('bar'); console.log(b.array); // prints ["bar"]  b.func.bar = 'baz'; console.log(a.func.bar); // prints baz 

In all these cases you are always working with the same object.

But if you assign a value to a property of the object, the property will be set/created on the object itself, not its prototype, and hence is not shared:

console.log(a.hasOwnProperty('array')); // prints false console.log(a.array); // prints ["bar"] a.array = ['foo']; console.log(a.hasOwnProperty('array')); // prints true console.log(a.array); // prints ["foo"] console.log(b.array); // prints ["bar"] 

If you want to create own arrays for each instance, you have to define it in the constructor:

function Foo() {     this.array = []; } 

because here, this refers to the new object that is generated when you call new Foo().

The rule of thumb is: Instance-specific data should be assigned to the instance inside the constructor, shared data (like methods) should be assigned to the prototype.


You might want to read Details of the object model which describes differences between class-based vs. prototype-based languages and how objects actually work.

Update:

You can access the prototype of an object via Object.getPrototypeOf(obj) (might not work in very old browsers), and Object.getPrototypeOf(a) === Object.getPrototypeOf(b) gives you true. It is the same object, also known as Foo.prototype.

like image 189
Felix Kling Avatar answered Sep 20 '22 07:09

Felix Kling


The behaviour is correct. [] is tranlated to new Array() in runtime, but only one such array is ever created.

In other words, Obj.prototype = {...} is executed just like any other assigment.

like image 23
glebm Avatar answered Sep 22 '22 07:09

glebm