nestet object instances - javascript

I have a problem with nested object and prototyping.
In following example I'm creating 2 instances of the object "o"
var o = function(){};
o.prototype = {
val : 1,
test : {
val2 : 1
}
};
var t1 = new o();
var t2 = new o();
t1.val = 5;
t2.val = 20;
t1.test.val2 = 5;
t2.test.val2 = 10;
console.log(t1.val) //5
console.log(t2.val) //20
console.log(t1.test.val2) //10
console.log(t2.test.val2) //10
My question is why t1.test.val2 === t2.test.val2, where t1 and t2 are different variables,
shouldn't they be totally separate ??
how to fix that code to have all objects and variables inside separate ?

When you define a new object, the prototype is copied, but objects in the prototype are not deep copied; they are copied by reference. Thus, each new o instance has a copied reference to the exact same member objects of the prototype.
Instead, make the test object in your constructor so each instance has its own copy:
var o = function(){
this.test = {
val2 : 1
}
};
o.prototype = {
val : 1 // this is fine, since primitive values aren't copied by reference
};

This happens because you are modifying a property of shared object (i.e. the prototype). Your code is basically the same as:
var val = 1;
var test = {
val2 : 1
};
var t1 = {
val: val,
test: test
};
var t1 = {
val: val,
test: test
};
t1.val = 5; // changing property
t2.val = 20; // changing property
t1.test.val2 = 5; // changing property of shared object
t2.test.val2 = 10; // changing property of shared object
To fix that simply don't use prototype, i.e.
var o = function(){
this.val = 1;
this.test = {
val2 : 1
};
// test is no longer shared, exists per instance
};

Related

Clone object with function

I wanted to clone original object and function without reference, is my code consider the correct way to clone object and function?
var apple = new function() {
this.type = "macintosh";
this.color = "red";
}
function aaa() {
return this.color + ' ' + this.type + ' apple';
};
var a = JSON.parse(JSON.stringify(apple))
var b =
JSON.parse(JSON.stringify(apple));
console.log(a)
a.getInfo = aaa
b.getInfo = aaa
a.color='green' // only a is green color
console.log(a.getInfo())
console.log(b.getInfo())
Try this function:
var clone = function (object) {
// Copy everything that is not an object
if (object == null || typeof(object) !== 'object') {
return object
}
// Calling constructor
var temp = new object.constructor()
// Recursively cloning children
for (var key in object) {
temp[key] = clone(object[key])
}
return temp
}
Test:
var test = { a: 0, b: function () { console.log(1) } }
var cloned = clone(test)
https://jsfiddle.net/feshcdLe/1/
For cloning objects, you can use Object.assign and set the first argument as an empty object.
For example
const clone = Object.assign({}, apple.call({}));
const result = aaa.call(clone);
console.log(result);
//=> red macintosh apple;
I made use of Function.call here simply because I don't know if you meant to access the global this or a different scope or what. If you do know what your this is referring to, then you can simply do.
const clone = Object.assign({}, this);
const result = aaa();
console.log(result);
MDN Object.assign
MDN Function.call

node.js how to make one variable change apply to another one aswell?

Is there some kind of way of having some kind of "shared" variable? What I want to do is this:
var id = 5;
var player = new Player(id);
var array1[0] = player;
var array2[0] = player;
array1[0].id = 8
console.log(array1[0]); //8
console.log(array2[0]); //8
In JavaScript, you do not store an object directly in a variable, but rather a reference to the object.
That means, you can have two variables that point to the same object - you simply copy the reference:
var a = {test: "test"};
var b = a;
console.log(a === b) // true
In this case, if you mutate the object via a and later read it via b, you will see the changes.
With the right implementation of Player, you can make that work for you:
var Player = function(id) {
this.id = id;
}
Player.prototype.setId = function(id) {
this.id = id;
}
Player.prototype.getId = function() {
return this.id;
}
var player = new Player(5);
console.log(player.getId()); // 5
var arrA = [];
var arrB = [];
arrA.push(player);
arrB.push(player);
console.log(arrA[0].getId()); // 5
console.log(arrB[0].getId()); // 5
arrA[0].setId(10);
console.log(arrA[0].getId()); // 10
console.log(arrB[0].getId()); // 10
Check MDN for more info on working with objects.

How to turn an undefined var to an object, inside a function

There is something I can't find an answer or an explanation for. Let's take for example the following code:
function fn(x){
x = {value: 10};
}
var a;
fn(a);
alert(a.value); //a is undefined
Shouldn't a = {value: 10}; as we passed it through that function?
The x is locally scoped. You are passing only values and not references. So you might need to return and assign like this:
function fn(x){
x = {value: 10};
return x;
}
var a;
a = fn(a);
From an awesome article:
When passing in a primitive type variable like a string or a number, the value is passed in by value. This means that any changes to that variable while in the function are completely separate from anything that happens outside the function.
function myfunction(x)
{
// x is equal to 4
x = 5;
// x is now equal to 5
}
var x = 4;
alert(x); // x is equal to 4
myfunction(x);
alert(x); // x is still equal to 4
Passing in an object, however, passes it in by reference. In this case, any property of that object is accessible within the function.
function myobject()
{
this.value = 5;
}
var o = new myobject();
alert(o.value); // o.value = 5
function objectchanger(fnc)
{
fnc.value = 6;
}
objectchanger(o);
alert(o.value); // o.value is now equal to 6

What is the portable way of setting prototype property after an object is created?

I have a JavaScript object created from JSON. I really need to set its prototype property to be a different object because of JS5 getters and setters. Here is an example of what I need that works on Chrome:
function MyObj() { }
MyObj.prototype = {
get myProp : function () { return this._myProp; },
set myProp : function (arg) { this._myProp = arg; }
}
... stuff ...
var instance = JSON.parse(result);
instance.constructor = MyObj;
instance.__proto__ = MyObj.prototype;
With this code, I can get and set properties on instance using the getters and setters defined in the prototype. However, this is not portable and will not work on IE, (nor node, I think).
What is the proper and portable way of doing this?
Think the other way around:
Create a new instance of MyObj and then copy the properties of instance to it. Or give MyObj a constructor that does that, when you provide it with an argument:
function MyObj(instance) {
if (instance) {
//copy properties
This way you may be even able to do
var instance = new MyObj(JSON.parse(result));
You could try using a JSON reviver function.
function revive(json) {
var m = new MyObj(), y;
return JSON.parse(json, function(k, v){
if (!y) y = this;
return k == "" ? m : this == y ? m[k] = v : v
});
}
Call revive('... a json string ...'), it will spit out an instance of MyObj with the properties defined in the JSON string.
Caveat: this will only work if the first item in your JSON object is a primitive value. If that's not possible in your case, here's a rather ugly workaround:
function revive(json) {
var m = new MyObj(), c = json.charAt(0), y, a;
if (c == '[') {
a = json = '[0,' + json.substring(1);
} else if (c == '{') {
json = '{"#":0,' + json.substring(1);
}
return JSON.parse(json, function(k, v){
if (!y) { y = this; return; }
return k == "" ? m : this == y ? m[a ? k - 1 : k] = v : v
});
}

JavaScript prototype structure and objects

I'm new to the prototype structure, and I'm having trouble figuring this one out. Here's my JavaScript code.
var Game = function ()
{
//some variables
};
Game.prototype.block =
{
spawn: function () {
var t1 = new this.inst;
},
inst : {
x: 5,
y: 0,
type: ''
}
};
When I try to create a new object "inst" I get the following error:
TypeError: object is not a function. What am I doing incorrectly?
If you want to create objects that inherit from the inst object, you can do that using Object.create, with var t1 = Object.create(this.inst);.
var Game = function () {
//some variables
};
Game.prototype.block = {
spawn: function () {
var t1 = Object.create(this.inst);
},
inst : {
x: 5,
y: 0,
type: ''
}
};
So then your code would look something like this;
var game = new Game();
game.block.spawn();
And the .spawn() method would have a variable that references an object that inherits from the Game.prototype.block.inst object.
First of all, inst is not defined within the scope of Game. So, this which refers to Game doesn't have any properties called inst. Secondly, inst must be followed by () to indicate a call to the constructor, which you are missing here.
I guest you need a static factory method to create new "inst". is the below code what you need? you call the Game.spawn method to generate a new inst, and you can put this method in setInterval.
function Game() {
//some variables
}
Game.spawn = function() {
function Inst() {
this.x = 5;
this.y = 0;
this.type = '';
}
return new Inst;
}
var inst1 = Game.spawn();
inst1.x = 1; //test inst1
console.log(inst1.x);
var inst2 = Game.spawn();
inst2.x = 2; //test inst2
console.log(inst2.x);
var inst3 = Game.spawn();
inst3.x = 3; //test inst 3
console.log(inst3.x);

Categories