Javascript replace/modify the object that a variable points to? - javascript

I have a variable pointing to an object and would like to replace that object with another modified one. Is there any Javascript function that can do what my hypothetical "assign" function does in the example console session below?
var x = [[1,2,3], [4,[8,2,[1,4,"Delete Me"],4],6]]
var y = getSubArrayWithString(x) // Equivalent to y = x[1][1][2] in this case
JSON.stringify(y)
>>> "[1,4,"Delete Me"]"
var newY = y.filter(item => item !== "Delete Me")
y.assign(newY) // Equivalent to x[1][1][2] = newY
JSON.stringify(x)
>>> "[[1,2,3],[4,[8,2,[1,4],4],6]]"
If I do y = newY that just reassigns the y variable to point at the newY object, it doesn't modify x.
I know I could modify y in place using splice, but that won't work when I'm applying more complex changes to get newY

Ideally getSubArrayWithString() would return a reference to the parent of the array you are interested in modifying (and maybe even the index you want). Then it's easy:
var x = [[1,2,3], [4,[8,2,[1,4,"Delete Me"],4],6]]
var [y, ind] = [x[1][1], 2] // getSubArrayWithString returns parent and index
y[ind] = y[ind].filter(item => item !== "Delete Me")
console.log(x)
If your really stuck with just the array reference, you can use splice() to alter the array rather than overwrite it. You could even splice() everything and reassign the new values, but this seems pretty inefficient:
var x = [[1,2,3], [4,[8,2,[1,4,"Delete Me"],4],6]]
var y = x[1][1][2]
var newY = y.filter(item => item !== "Delete Me")
y.splice(0,y.length) // sketchy, but works
Object.assign(y, newY)
console.log(x)

Related

Why doesn't the array store the composite type in a proper way in JavaScript?

I have a function that generates numbers within a range.
I created a composite type like this:
var cowPosition = {
x: 0,
y: 0
};
I also created an array:
var positionsArray = [];
then, I proceed to iterate to fill the array with the composite type.
All of this is inside a function which returns the array.
Here's the function:
function generateCowPositions(numberOfCows){
var positionsArray = [];
var cowPosition = {
x: 0,
y: 0
};
var x,y;
for (var i = 0; i < numberOfCows; i++) {
x = randomPosition(0,5);
y = randomPosition(0,5);
x = x * 80;
y = y * 80;
cowPosition.x = x;
cowPosition.y = y;
positionsArray[i] = cowPosition;
}
return positionsArray;
}
When I run it, it fills the whole array with the last two generated coordinates.
There is no "composite type" in JavaScript. What you are referring to is called an object.
The problem you are having is that objects are passed by reference, not by value. This means that if you store an object into a variable called a and modify it in some function, the value stored in a will be modified too.
What you need to do is:
function generateCowPositions(numberOfCows) {
var positionsArray = [];
// note: cowPosition object is not needed anymore, so I've removed it
var x, y;
for (var i = 0; i < cantidadVacas; i++) {
x = randomPosition(0, 5);
y = randomPosition(0, 5);
x = x * 80;
y = y * 80;
// create a new object in every intration
positionsArray[i] = {
x: x,
y: y,
};
}
return positionsArray;
}
Because there is only one instance of cowPosition in your code. So every iteration of your loop simply changes that one object, and at the end of the loop you simple keep the result of the last iteration.
Each index in the array is pointing to the exact same object, being cowPosition
I'm not sure what you are trying to accomplish 100%, but you should create a new object at each iteration. There isn't a need to initialize x and y in the object.
Simply:
function generateCowPositions(numberOfCows){
var positionsArray = [];
var cowPosition = {}
var x,y;
for (var i = 0; i < cantidadVacas; i++) {
x = randomPosition(0,5);
y = randomPosition(0,5);
x = x * 80;
y = y * 80;
cowPosition.x = x;
cowPosition.y = y;
positionsArray[i]= Object.assign({}, cowPosition);
}
return positionsArray;
}
JavaScript is an object-oriented language where objects are passed by-reference, not by-value. I suspect you're thinking of C and C++ where struct/class values are by default copied in their entirety by the = operator. In JavaScript it's closer to C# and Java where object / non-primitive types have their references copied instead.
Objects in javascript are passed as references.
positionsArray[i] = cowPosition; sets positionsArray[i] to a reference to the cowPosition object.
After the loop, all array elements reference the same cowPosition object. Therefore, since each loop of the array changes the underlying cowPosition object, all the array elements appear to have the same x and y position.
A simple solution to this problem would be to shallow copy the cowPosition object inside the loop, such that each array element references a difference position object and changing the underlying cowPosition object has no effect on the shallow copies inside the positionsArray, like so:
positionsArray[i] = JSON.parse(JSON.stringify(cowPosition));
This works by converting the object to a string and back again using javascript's native JSON implementation.

Swapping two elements x and y positions

I am trying to swap two images .x and .y positions. The method I am using fails because I think once I do first swap they point to same positions or something, seems only one moves to new position hope this makes sense.
theSequence[i].onClick = function(e){
firstObject.push(this);
if(firstObject.length == 2){
firstObject[0].x = firstObject[1].x;
firstObject[0].y = firstObject[1].y;
firstObject[1].x = firstObject[0].x;
firstObject[1].y= firstObject[0].y;
}
You have to use temp variable:
if(firstObject.length == 2)
{
tempX = firstObject[0].x;
tempY = firstObject[0].y;
firstObject[0].x = firstObject[1].x;
firstObject[0].y = firstObject[1].y;
firstObject[1].x = tempX;
firstObject[1].y= tempY;
}
There seems to be a problem with your logic.
When you do:
firstObject[0].x = firstObject[1].x;
firstObject[0].y = firstObject[1].y;
Both images will have the same x and y coords. So, when you do:
firstObject[1].x = firstObject[0].x;
firstObject[1].y= firstObject[0].y;
It's redundant. You need to store the x and y of your firstObject[0] in variables before changing them and then assign the value of those variables to firstObject[1].
To avoid temp variable in ECMAscript you can use:
[a, b] = [b, a];
(like in python) or use this hack:
a = -(b = (a += b) - b) + a;
source

In which order are variables assigned in Javascript?

Apparently this is identical in my Firebug console:
var x = "A", y = x;
x + y === "AA";
and
var x = y, y = "A";
x + y === "AA";
Is this standard ECMAScript behaviour, that the order doesn't play a role in comma-separated var assignments?
Edit: The "mystery" is solved. I tested the first example first, then cleared the console and ran the second. However, at this time, y and x were already defined. If you run the JSFiddle provided by David Thomas you always get an "undefinedA". Case settled.
var x = y; will raise an exception if y is not defined.
However, the window object is the default context for Javascript interpreters embedded in browsers. If you previously issued:
y = "A";
Then you actually assigned "A" to window.y, therefore var x = y; becomes valid and assigns window.y to x.

Why is the U variable set to NULL in this interesting Javascript code fragment?

i have a javascript code fragment as
var u = {};
var x = y = z = {"cvalue":"cell", "call":function(){alert(this.cvalue);}};
(function(){u=x;/*change all cvalue in x,y, z, u*/ u.cvalue = "notcell";})();
if(u == x && x == y && y == z && z == u){
u.call();
}
//only u goes to null
u = null;
//x,y,z stay same
alert(x.cvalue);
wondering why u = null only applies for u?
Variables don't actually hold an object, but simply hold a reference to one. By assigning u to null, you're dropping the reference that u had to the object.
A more basic example:
var x = { 'name': 'Bob' };
var y = x;
console.log(x); // Object { name="Bob"}
console.log(y); // Object { name="Bob"}
y.name = 'Jack';
console.log(x); // Object { name="Jack"}
console.log(y); // Object { name="Jack"}
x = null;
console.log(x); // null
console.log(y); // Object { name="Jack"}
Note how our object isn't held in x. It's held somewhere in memory, and x is referring to it. When we do y = x, we copy the reference to y, and therefore y begins to refer to the same object. Setting x to null simply drops the reference that x holds to the object, leaving the actual object unaffected. If we were to set y to null, or to anything else, the garbage collector would eventually pick up the object for destruction.
Daniel is right, but you have to be careful because in Javascript you are sometimes dealing with a copy, and othertimes dealing with the original. For example...
var a = new Object();
a.foo = new function(){alert("I exist")};
var b = a;
b.foo = null;//this erases the function from both a and b (technically, there is only one since a and b point to the same place in memory).
a.foo();//this now fails since there is no longer a function called foo
b = null;//this does NOT affect a in any way as per Daneiel Vassallo's explanation.
You are assigning the exact same object to x, y and z, not a copy of it's value, but the exact same object.
In pseudo code:
var u = OBJECT_A // u points to OBJECT_A
var x = y = z = OBJECT_B // x y and z points to OBJECT_B
(function(){
u=x; // Drop reference to OBJECT_A and point to OBJECT_B
/*change all cvalue in x,y, z, u*/
u.cvalue = "notcell"; //Changes the cvalue in OBJECT_B
// Remember x,y,z, and u points to OBJECT B
// so x.cvalue, y.cvalue, z.cvalue and u.cvalue is the same
})();
if(u == x && x == y && y == z && z == u){
u.call();
}
//only u goes to null
u = null; // Drop reference to OBJECT_B and point to NULL.
//x,y,z still points to OBJECT_B
alert(x.cvalue);

Is variable updated "by reference"?

I have the following simple script.
<script>
SPC = {
a : [10],
b : 10,
t: function()
{
y = this.a;
z = this.b;
y[0]++;
z++;
alert('this.a[0] = ' + this.a[0] + '\nthis.b = ' + this.b)
}
}
SPC.t();
SPC.t();
</script>
Running it in your browser will display two alert boxes with:
this.a[0] = 11
this.b = 10
and
this.a[0] = 12
this.b = 10
The question is, why does the value of this.a[0] increment? I'm assigning "y = this.a" and updating element of "y" as "y[0]++;"?
At the same time, exactly the same thing is happening with "b": "z = this.b; z++". Yet, "this.b" remains equal to 10.
How can I change value of "y[0]" in the local scope without affecting "this.a"?
Any ideas?
Thanks!
a is an array, and you're simply copying a reference to the array into y. You need to copy the array a's contents into a new array y instead (using Array.slice() (y = a.slice() in your case) is the easiest way).
(Or, if you only need a[0], you can set y = a[0]. Subsequent changes to y will not affect a[0], since you are copying the value.)
See the "Javascript Arrays Are Assigned By Reference" and "Passing Arrays As Values" sections of this article for more information.
Try Array.slice() function.
y = this.a.slice()
This will create a copy of a array and assign it to y. So modification of y won't affect a.
you are assigning the address value of array a and b into y and z.
therefore, y, and z become the exact copy of a and b.
instead of assigning address value into y and z.
you just need to take content value of a and b and assign them into y and z
y = a[0]
z = b[0]
and then y++

Categories

Resources