This question already has answers here:
Javascript object members that are prototyped as arrays become shared by all class instances
(3 answers)
Closed 8 years ago.
I don't understand why the array is shared between two instances while the primitive type is not. Can someone please explain?
MyObject = function() {};
MyObject.prototype = {anArray : [],aString : ''};
var c1 = new MyObject();
c1.aString = 'a';
c1.anArray.push('a');
var c2 = new MyObject();
console.log(c2.aString);
console.log(c2.anArray);
Strings are immutable, Arrays are mutable. You're replacing the String, but modifying the Array.
You'll get the same behavior between Arrays and Strings if you overwrite the Array instead of modifying it.
MyObject = function() {};
MyObject.prototype = {anArray : [],aString : ''};
var c1 = new MyObject();
c1.aString = 'a';
c1.anArray = []
c1.anArray.push('a');
var c2 = new MyObject();
console.log(c2.aString); // ''
console.log(c2.anArray); // []
So it only makes sense to put an Object or Array on the prototype if you're planning on allowing all instances to observe changes to it. Otherwise, just put it directly on the instance.
MyObject = function() {
this.anArray = [];
};
MyObject.prototype = {aString : ''};
When you assign
c1.aString = 'a'
you are not assigning to the aString field in the prototype. A new field called aString is created directly in the c1 object and hides the aString field in the prototype.
Meanwhile, when you call
c1.anArray.push('a');
there is no anArray field in c1, so you're referencing the anArray in prototype. You can test this by doing
c1.anArray = new Array();
and note that a new property anArray is created in c1, not interfering with anArray in the prototype. In this case,
console.log(c1.anArray);
console.log(c2.anArray);
would have different outcome, as c2 would still refer to the anArray in prototype.
If there is a field with the same name both directly in the object and in the prototype (or even further in the prototype chain), and you request a value of this field, the interpreter first looks directly into the object, only then up the prototype chain, until it finds the field somewhere.
However, if you assign a value to a field, it is always done directly in the object, never in its prototype.
Related
Here I have a simple code to understand how Object.create() works. Here I have a common object to be used as prototype which is prototypeObj.newObj is an object which has its prototype set to prototypeObj. Here I have another object called session which has a property called anotherObj, and anotherObj has the same prototype as newObj. But adding new value to a property called foo which resides in the prototype of anotherObj , affect newObj too. Why am I experiencing this behaviour?
Code:
var prototypeObj = {
foo: [],
addItemToFoo: function(add) {
this.foo.push(add);
}
}
function create(fooVal) {
var myProto = Object.create(prototypeObj);
myProto.foo = fooVal;
return myProto;
}
var newObj = create([1, 2]); // initialized with [1,2]
session = {
anotherObj: create(newObj.foo) // initialized with [1,2]
}
session.anotherObj.addItemToFoo(6); // pushed 6 to session.anotherObj.foo
console.log("newObj.foo is " + newObj.foo); // newObj also get 6 pushed to its foo property
console.log("anotherObj.foo is " + session.anotherObj.foo);
foo is an array, it works by reference.
anotherObj: create(newObj.foo)
You are copying the reference here, so both your old and new object will have the same array reference to insert elements in. If you want to have to different array references, you should first copy it like this create(newObj.foo.slice())
https://jsfiddle.net/x8ftnh82/
Is prototype inheritance behaving differently based on the type? Is the contextual reference THIS working different in these two cases? Why in this examples, one is accessing to the prototype and the other one is creating a new property to the object?
var Player = function(){};
Player.prototype.name = '';
Player.prototype.set_name = function(name){this.name = name;}
var p1 = new Player();
var p2 = new Player();
p1.set_name('Johanna');
Value return by these two:
// Checking object properties
>p1
Player {name: "Johanna", set_name: function}
>p2
Player {name: "", set_name: function}
// Checking prototypes
>p1.__proto__
Object {name: "", set_name: function}
>p2.__proto__
Object {name: "", set_name: function}
But if I do the Player with name as an object property, the function set_name is modifying the prototype.
var Player = function(){};
Player.prototype.name = {};
Player.prototype.set_name = function(name){this.name['first_name'] = name;}
var p1 = new Player();
var p2 = new Player();
p1.set_name('Andrew');
Value return by these two:
// Checking object properties
>p1.name
Object {first_name: "Andrew"}
>p2.name
Object {first_name: "Andrew"}
// Checking prototypes
>p1.__proto__.name
Object {first_name: "Andrew"}
>p2.__proto__.name
Object {first_name: "Andrew"}
Why is this happening? What concept(s) am I missing?
Inheritance chain
When you create an object with a constructor function, the inheritance chain goes like this, for lookup.
The current object will be searched.
Prototype of the parent will be searched.
Prototype of the parent's parent will be searched.
...
And finally the global object will be searched. If it is not found anywhere, undefined will be returned. If the value being looked up is found in any of these levels, it will be returned immediately.
Note: Assignments won't go up the inheritance chain. If you assign a value to an attribute of an object (if it is not present it will be created) then the value will be assigned to that attribute.
First case:
You are doing
this.name = name;
So,
p1.set_name('Andrew');
creates a new name attribute in p1 and stores Andrew in it. And when you tried to print p1, the name was looked up on p1 and it was found in p1 itself. So, Andrew was returned. But, when you printed p2, name is not found in p2. It goes up in the hierarchy and finds the name in parent's prototype. So, it returns the empty string.
Second case:
You are doing
this.name['first_name'] = name;
So,
p1.set_name('Andrew');
looks up name in p1. Because you are trying to access 'first_name' on this.name. So, it tries to retrieve name attribute. It doesn't find it in p1, so goes up and finds it in the parent's prototype. It is an empty object and name gets assigned to first_name attribute of that object.
We know that p2's prototype is the same as p1's prototype. We can confirm that like this
console.log(p1.__proto__ === p2.__proto__);
# true
So, when you look up p2's prototype, which is the same as p1's prototype, the name Andrew is found.
As a general case variables and such are set in the constructor.
For more info on the subject and a better explanation than i can do reference here: http://javascriptweblog.wordpress.com/2010/06/07/understanding-javascript-prototypes/
// Constructor
function Player() {
this.names = '';
};
// Public Method
Player.prototype.set_name = function(name){
this.name = name;
}
// Static method
Player.walk = function() {}
var player1 = new Player();
player1.set_name('John Doe'); // fires the public method
Player.walk(); // fires the static method
This question already has answers here:
Deleting Objects in JavaScript
(14 answers)
Closed 8 years ago.
Suppose i have an Array of objects in javascript :
var obj0 = new Object();
var obj1 = new Object();
var obj2 = new Object();
var obj3= new Object();
var array = new Array(obj0,obj1,obj2,obj3);
if i write :
array[1] = null;
this will give me [obj0,null,obj2,obj3] what was nulled is the array case not the object itself; the obj1 won't really be nulled in the memory.
How to null an object by accessing it via the array ?
You just need to remove all references to the object, including the obj1 reference. Then the garbage collector will take care of the rest.
However, if your obj1 variable is a local variable (as it appears to be in your code snippet), you can just leave the reference as is. When the enclosing method returns, the local variable will be cleaned up, and subsequently, the nulled object as well.
I found a good article on Smashing Magazine that looks relevant to your question.
It’s not possible to force garbage collection in JavaScript. You
wouldn’t want to do this, because the garbage collection process is
controlled by the runtime, and it generally knows best when things
should be cleaned up.
http://coding.smashingmagazine.com/2012/11/05/writing-fast-memory-efficient-javascript/
i think "splice()" will help:
http://www.w3schools.com/jsref/jsref_splice.asp
var obj0 = new Object();
var obj1 = new Object();
var obj2 = new Object();
var obj3= new Object();
var array = new Array(obj0,obj1,obj2,obj3);
array.splice(1); // kill index 1
The result: [obj0,obj2,obj3].
What if you tried to write it this way?
var array = new Array();
array[0] = new Object();
array[1] = new Object();
array[2] = new Object();
array[3]= new Object();
array[1] = null;
As commented Kpower, writting :
var array = [{}, {}, {}, {}];
or
var array = new Array(new Object(),
new Object(),
new Object(),
new Object());
and when nulling any array cell like :
array[1] = null;
this will effectively remove the reference for the object so it will be garbage collected.
Kind of strange thing is happening with my code. What I observe is something like this:
var prototype = {
property : "",
array : []
}
var objectArray = [];
function myFunction {
objectArray[0] = Object.create(prototype);
objectArray[1] = Object.create(prototype);
objectArray[0].property = "Hello 1";
objectArray[0].array.push("Hello 1");
objectArray[1].property = "Hello 2";
objectArray[1].array.push("Hello 2");
// At this point when running the program I get:
// objectArray[0].property == "Hello 1"
// objectArray[1].property == "Hello 2";
// objectArray[1].array == objectArray[1].array == prototype.array
// == ["Hello 1", "Hello 2"]
}
What I want, and expected, was two separate arrays for the two objects. What am I missing here?
In JavaScript, objects are copied by reference, so both objectArray objects are simply references to the same object ( prototype ). You need to clone the object or create instances using the new keyword and a constructor to create separate objects.
Example on how to do it using the new keyword:
var prototype = function() {
this.property = "";
this.array = [];
};
objectArray[0] = new prototype();
objectArray[1] = new prototype();
You can also do:
var prototypeFactory = function() {
return {
property: "",
array: []
};
};
objectArray[0] = prototypeFactory();
objectArray[1] = prototypeFactory();
The prototype object exists the same as the [[Prototype]] for each object. They don't get a fresh copy when you use Object.create().
You'd need to use assignment, which never walks the prototype chain.
I wonder if you aren't asking yourself "why does it work for property, but not for array?". The fact is, it doesn't work for property either, JavaScript is fooling you.
When objects share the same prototype, one must consider that:
All properties of the prototype are shared by the objects that inherit from that prototype.
You cannot assign to properties of the prototype, only read them (unless it's an accessor property, but let's keep that aside).
So what's actually happening here:
objectArray[0].property = "Hello 1";
objectArray[1].property = "Hello 2";
is that a new own property called "property" is being created on each object, while prototype.property remains untouched. The array property is behaving differently because you're not assigning to it, you're accessing prototype.array and calling the push method on it.
Don't forget that Object.create() isn't yet standardized, and won't work in IE8 or FF3.6. A simple work-around to clone an object is to use the JSON object:
function clone(obj) {
return JSON.parse(JSON.stringify(obj));
}
I understand that there are two ways of creating classes in JavaScript
var MyObj = function(val)
{
this.vari = val;
}
Where val will be a non static member.
Whereas,
var MyObj = new Object();
MyObj.vari = "";
This is a single object so members of it here will act like static members. My question is that how do we have both static as well as non static content in same class?
There are no classes in JavaScript, only objects.
When you create a new object you are "extending" from the function's prototype, not the function itself. In order to make a variable or function appear to be static you would have to attach it to the function used to create the object, and not its prototype.
js> var Foo = function(){ this.member = "member"; };
js> Foo.staticMember = "staticMember";
js> var f = new Foo();
js> Foo.member;
undefined
js> Foo.staticMember;
"staticMember"
js> f.member;
"member"
js> f.staticMember;
undefined
Using your first example:
var MyObj = function(val) {
this.vari = val;
};
MyObj.var2=value;
Will create a new "static" property callable as:
var o = MyObj.var2;
The first one initializes the MyObj variable with the anonymous function - it does not create the class. The MyObj may be later used as the object constructor that initializes one object field - vari. There is nothing "statis" in OOP meaning.
The second one creates the object of the Object type and initializes its property. Again, there is nothing static.
In OOP "statis" means the member of the class, e.g. variables and objects that belong to class definition. For example, the following schema demonstrates this concept:
function MyClass() {
this.objectProperty = "I'm object property";
// the following demonstrates initialization of
// the object property from class (static) property:
this.varFromStatic = MyClass.classProperty;
}
MyClass.classProperty = "I'm class (static) property";
var obj = new MyClass();
// now obj.varFromStatic contains "I'm class (static) property"