When I put an object into array using push method and then change the value of the object, the value of the object in the array also changes. How to prevent it?
function onLoad() {
let array = []
let object = {}
object[1] = [1,2]
array.push(object)
object[1] = [1,3]
console.log(array)
}
onLoad();
I would like the code console [{1,2}] but it will console [{1,3}].
Would anyone know how to fix this?
In JavaScript, Complex data types(Objects and arrays) are copied by reference whereas primitive data types(Strings, Numbers, and Boolean) are copied by value
Simply put , Pass by reference will not create a copy instead refer to the same memory.
So original objects and arrays will be changed
Copy by value will create a copy of the value and hence original value will not be changed
function change(array1){
array1[0] = "changed";
}
var original = ["original"]
change(original)
console.log(original)
function changePrimitive(input) {
input = "changed"
}
var original = "original"
changePrimitive(original)
console.log(original);
Related
I'm having a strange situation in JavaScript where I am creating an Object and then passing it as an Argument to a Function which then updates the values and then returns a new updated Object.
function objBuild() {
var obj_old = {}; // original object
var obj_new = {}; // updated object
// set values for original object
obj_old.val01 = "val01_old";
obj_old.val02 = "val02_old";
obj_old.val03 = "val03_old";
// set values for new object using
// the original object as a template
obj_new = objUpdate(obj_old);
console.log(obj_old); // this shows obj_new data which I don't want
console.log(obj_new); // this shows obj_new data which I want
}
function objUpdate(obj) {
obj.val03 = "val03_new";
return obj;
}
I was expecting the new Object to be updated with the new Value, which it is, however the old Object is updated as well.
Maybe the function is taking the old Object as a reference and even though I'm returning a separate value it remembers what's happened to it?
I'm not sure but if that is the case is it possible to keep the old Object intact?
Please read: Is JavaScript a pass-by-reference or pass-by-value language?
In javascript, objects are "technically" passed by "reference". Hence, the original value is altered, because obj is, in fact, the original object.
You need to clone the object, and there is a vast scenario about "how" you should do that, since object may be shallow copied or deep copied. Read more about that here: What is the most efficient way to deep clone an object in JavaScript?
and here: How do I correctly clone a JavaScript object?
Anyway, to fix your issue, just use Object.assign on a brand new object to copy the values of the original object, for your case, it's just enough, despite I recommend you to read the above posts to learn when and how to properly copy objects.
function objBuild() {
var obj_old = {}; // original object
var obj_new = {}; // updated object
// set values for original object
obj_old.val01 = "val01_old";
obj_old.val02 = "val02_old";
obj_old.val03 = "val03_old";
// set values for new object using
// the original object as a template
obj_new = objUpdate(obj_old);
console.log(obj_old); // this shows obj_new data which I don't want
console.log(obj_new); // this shows obj_new data which I want
}
function objUpdate(obj) {
var _cloned = Object.assign({}, obj);
_cloned.val03 = "val03_new";
return _cloned;
}
objBuild();
You're not actually creating a new object, you're setting the old object to the new object. So you're correct, the old object value is still being referenced.
If you want to make a new object, and you don't have any nested objects, I would use Object.assign(). This makes a shallow copy of the object. You could do something like this:
obj_new = objUpdate(Object.assign({}, obj_old));
This will create a new object with the enumerable properties of the old object.
If you have nested objects, these will still be copied by reference, so I would loop over the object and copy the properties that way.
Remember that objects, including arrays are passed by reference while strings, booleans and numbers are passed by value.
Here, you are passing object(by reference) so it is modifying the values of old object. Both old and new objects are pointing to the same value.
function objBuild() {
var obj_old = {}; // original object
var obj_new = {}; // updated object
// set values for original object
obj_old.val01 = "val01_old";
obj_old.val02 = "val02_old";
obj_old.val03 = "val03_old";
// set values for new object using
// the original object as a template
obj_new = objUpdate(obj_old);
console.log(obj_old); // this shows obj_new data which I don't want
console.log(obj_new); // this shows obj_new data which I want
}
function objUpdate(obj_old) {
var obj = JSON.parse(JSON.stringify(obj_old));
obj.val03 = "val03_new";
return obj;
}
objBuild();
Reaching out for an explanation of what is happening in this code snippet.
The object variable options is declared and assigned to an empty object. Then another object variable parsedData is declared and set with any number of properties, including -> options that is assigned to empty options object.
During processing, options object is updated with new key/value pairs inside of a forEach loop.
When you output parsedData.options, it IS updated and you see references to the new key/value pairs.
I assumed this was javascript variable hoisting. I googled for a few minutes, but could not confirm.
I thought it was a good question to ask on StackOverFlow. Can someone confirm or provide an explanation?
FYI - The better solution is to update parsedData.options NOT options.
Code Snippet
var options = {},
parsedData = {
options: options
};
["foo","bar"].forEach(function(name,index) {
options[name] = index
})
parsedData.options
// options are Updated - Output: Object {foo: 0, bar: 1}
In Javascript, Objects are passed by reference and primitives (String, Number ...) by value.
So when you assign a variable referencing an object to a new one, a reference to this object is passed, and when you update one, the other is updated too, which is normal because they are both pointing to the same object.
So that:
let a = 1;
let b = a;
a = 2;
console.log(b); // 1, because b got the value of a
and
let a = { z: 1 };
let b = a;
a.z = 2;
console.log(b.z) // 2, because b got a reference to the object
var arrN = [1, 2, 3];
function init(arr){
arr = [];
console.log(arrN) //output [1, 2, 3], expect []
}
init(arrN);
When using splice or push methods the array passed to a function is being modified. So I am trying to understand what is happening when using assignment operator, why it's not changing the array? is it creating the local var of the passed array?
Any help will be appreciated!
You need to distinguish between the variable and the actual object (the array). splice and push are changing the object.
arr = [] is just changing the variable, the old object just stays as it is.
There is a difference in assigning a different object to a variable or mutating the object currently referenced by a variable.
(Re)assigning
When you do an assignment like:
arr = []; // or any other value
... then the value that arr previously had is not altered. It is just that arr detaches from that previous value and references a new value instead. The original value (if it is an object) lives on, but arr no longer has access to it.
Side note: if no other variable references the previous value any more, the garbage collector will at some point in time free the memory used by it. But this is not your case, since the global variable arrN still references the original value.
Mutating
It is another thing if you don't assign a value to arr, but apply instead a mutation to it, for instance with splice, push, pop, or an assignment to one of its properties, like arr[0] = 1 or arr[1]++. In those cases, arr keeps referencing the same object, and the changes are made to the object it references, which is visible to any other variable that references the same object, like arrN.
Clearing an array
Now if you want to clear the array that is passed to your function, you must avoid to make an assignment like arr = .... Instead, use methods that mutate the array in place:
arr.splice(0)
Or, alternatively:
arr.length = 0;
Now you have actually mutated the array, which is also the array referenced by arrN.
In JavaScript, particularly when working with objects the assignment operator (=) has three jobs.
Assignment
Creating a new reference if the right side is an object.
Breaking any previous referencing and creating multiple assignments if both sides are objects.
Such as;
var a = [1,2,3], // a is assigned an array
b = a; // b is assigned just a reference to a
a = ["a","b","c"]; // b to a referral is now broken
// a is assigned with ["a","b","c"]
// b is assigned with [1,2,3]
same would apply if it was done in reverse order;
var a = [1,2,3], // a is assigned an array
b = a; // b is assigned just a reference to a
b = ["a","b","c"]; // b to a referral is now broken
// b is assigned with ["a","b","c"]
// a keeps it's existing assignment as [1,2,3]
Your are passing arrN to the console instead of passing arr. Also, you just call a function by its name, not by the keyword function. Here is the corrected code:
var arrN = [1, 2, 3];
function init(arr){
arr = [];
console.log(arr)
}
init(arr);
You have also declared init() with an argument arr, which is not needed in this case. What ever the value you pass to init(), the value of arr will be [] because you are reassigning it in the function.
While using array.push() to add values at the end of an array in angularjs will it create a deep copy of the pushed value inside the array or not.
No, you will be adding a reference to the original object to the array, not the value or a copy
var obj = { key: "value" }
var arr = [];
arr.push(obj);
obj === arr[0];
// true
No, Deep copy can be done via angular.copy.
For example.
var data = [{'name':'abc'}, {'name':'xyz'}];
var copiedOne = angular.copy(data);
In Javascript objects are always passed by reference unless you make a copy of it yourself.
Please give me answer use JavaScript code. How i can store data like this
let obj = new Object;
obj.prop = 5; // Good
// but when i put third value like obj.prop.newObjectInside= 5 /Return error/
// How i can do it? or for example
obj.prop.array = 5 // Return error
I need add third object or array inside and use this pattern in my loop.
Thank you and if you know some articles or reference please write me too.
Try
obj.prop = { array : 5 }
or since it seems like you desire it to be an array you can do
obj.prop = { array : [5] }
You should then be able to do array ops like so
obj.prop.array.push(value);
Note the key here is to ensure that the second child is initialized, so you have to at least have an empty array
obj.prop = { array : [] }