I'm having an issue with saving a variable value at a certain time in javascript. At a basic level, in the code below, I would like variable 'b' to keep the value it was assigned
var a = [];
var b = '';
var c = 'value';
a.push(c);
b = a;
console.log(b); // b = ["value"]
a.push(c);
console.log(b); // b = ["value", "value"], but i want it to be just ["value"]
I've seen various solutions to similar problems using closures such as in this question: Intentionally "freezing" a javascript variable using a self-executing function. I have tried that solution unsuccessfully in this Jsbin: http://jsbin.com/zusara/1/edit?js,console.
Any help would be greatly appreciated.
Thanks and best!
Assigning an array to a variable does NOT make a copy. Thus both a and b variables then point to the same array and any change made via either variable will show up in the other.
If you want a copy of an array in Javascript, then you have to explicitly make a copy of the array.
var a = [];
var c = 'value';
a.push(c);
// make shallow copy of a into b
var b = a.slice(0);
b now contains a completely separate array and modifications of a will not affect b.
Note: this is a shallow copy, not a deep copy and is the solution for arrays. A shallow copy doesn't not copy objects in the array or objects in those objects. Making a deep copy requires substantially more code, but is often not required and does not appear to be required in your case for the example you provided.
If you want a deep copy and want to include objects too, not just arrays (I provided the simple solution for a shallow copy of an array), you can see this reference there are plenty of options and debate here:
What is the most efficient way to deep clone an object in JavaScript?
One way to achieve this is by using the slice function.
Instead of:
b = a;
Try using:
b = a.slice();
Related
I am having trouble maintaining the original value of a variable after making new changes to the original variable.
Code:
(...)
data = Illumination.calculate_N(data)
data = Illumination.calculate_pi(data)
data = Illumination.calculate_kwh(data)
data = Illumination.calculate_ca(data)
let data_base = data
let ca_base = data.ca
let kwh_base = data.kwh
let pi_base = data.pi
(...)
data = Illumination.calculate_N(data)
data = Illumination.calculate_pi(data)
data = Illumination.calculate_kwh(data)
data = Illumination.calculate_ca(data)
let data_proposto = data
let ca_proposto = data.ca
let kwh_proposto = data.kwh
let pi_proposto = data.pi
-----------------------------------
EXAMPLE:
static calculate_ai(data){
data.ai = data.areaTotal*data.au
return data
}
It was expected that the original variable (date) would have its values changed, and this happens correctly, however, the variables data_base and data_proposto are not keeping their values
Both variables at the end of the calculation have the same values as the variable date
The variables ca_proposto, ca_base, and the like store their values correctly
Any idea?
The only interactions of the variables data_base and data_proposto were their creations with the data variable and their return of the function
OBS: If I use console.log () to view the value of the data_base variable before redoing the new calculations (Illumination.calculate_N (data)), the value of the variable appears correctly as it should, it is changed shortly after these calculations.
Because in both cases you are assigning not the object itself in the current state, but a reference to that object. What you need to do is to clone the object so the state is frozen at that point.
Simple Clone (Shallow Copy)
let data_base = Object.assign({}, data); //you get a clone of data
let data_proposto = Object.assign({}, data);
The limitation here is that it only does a shallow copy. See Deep Copy below for further explanation.
JSON Clone
This is a quick-and-dirty way to clone as it converts a JSON object to a string, and then back. i.e. you are no longer getting a reference, but a new object.
let data_base = JSON.parse(JSON.stringify(data));
let data_postero = JSON.parse(JSON.stringify(data));
But this won't work if your object is not JSON-safe.
Deep Copy
The least elegant method is probably safest. It deep copies the properties over into a new object. The key difference with Object.assign() is that it copies the values of nested properties, whereas Object.assign() copies the reference to nested objects.
So with Object.assign() any subsequent changes in your nested objects will affect all versions of your "clones". This won't happen if your clones only have property values of those nested objects at the time of cloning – these values are not affected by any changes to the nested objects.
const deepCopy = function(src) {
let target = {};
// using for/in on object also returns prototype properties
for (let prop in src) {
// .hasOwnProperty() filters out these prototype properties.
if (src.hasOwnProperty(prop)) {
target[prop] = src[prop]; //iteratively copies over values, not references
}
}
return target;
}
let data_base = deepCopy(data);
let data_postero = deepCopy(data);
#chatnoir Defined the problem very well, But I do not agree with his JSON serialization solution due to the below probleam:
You will lose any Javascript property that has no equivalent type in
JSON, like Function or Infinity. Any property that’s assigned to
undefined will be ignored by JSON.stringify, causing them to be missed
on the cloned object.
My suggestion to perform deep copy is to rely on a library that’s well
tested, very popular and carefully maintained: Lodash.
Lodash offers the very convenient clone and deepclone functions to perform shallow and deep cloning.
Lodash has this nice feature: you can import single functions separately in your project to reduce a lot the size of the dependency.
Please find the running sample code here: https://glitch.com/edit/#!/flavio-lodash-clone-shallow-deep?path=server.js:1:0
You are using the same variable data inside and outside functions.
ie; data is in the global scope.
static calculate_ai(data){
data.ai = data.areaTotal*data.au
return data
}
even though you are expecting the scope of the variable data inside the method calculate_ai to be limited to that method, it is not the case. data is in global scope and therefore, the value changes inside the method for the variable affects outside as well.
An effective solution is to use a different variable inside the method.
A variable is like an octopus tentacle, and not as a box (as it’s commonly described). In this analogy, the variable's name can be thought of as the name of a tentacle.
A variable (tentacle) holds on to a value in what’s called a binding. A binding is an association of a variable to a value: x = 1.
In JavaScript, if a variable b holds on to variable a, changing the value to which variable a holds onto, will change the value to which variable b holds onto, as b and a are referencing to the same value:
let a = {key: 1}
let b = a
console.log(`a: ${a.key}`) // -> 1
console.log(`b: ${b.key}`) // -> 1
a.key = 2
console.log(`a: ${a.key}`) // -> 2
console.log(`b: ${b.key}`) // -> 2
a = {key: 3} // This will point variable 'a' to a new object, while variable 'b' still points to the original object.
console.log(`a: ${a.key}`) // -> 3
console.log(`b: ${b.key}`) // -> 2
Note: I assume this question has been asked a million times before but I didn't know what to search for.
The question is very simple. Array in javascript seems to be set by reference. How can i set it by value. Meaning, even if I empty the array a, I want array b to be the copy of a i.e., I want alert(b) to alert ['1','2','3']
var a = ['1','2','3'];
var b = [];
b = a;
a.length = 0;
alert(b);
here is a jsfiddle http://jsfiddle.net/e5mQM/
Yes, setting a = b; will make both variables point to the same array / object, so you have to copy the array instead of just referencing it :
b = a.slice();
javascripts slice() method returns a new array sliced based on the parameters given, and if called without parameters it will return a new shallow copy of the entire array.
I would like to understand well something i observe more and more.
In some circonstances, different instances from a same model change their attributes the same way (if i have 2 UserModel A and B, if i change A, B will be affected the same way).
I observed some practical cases:
When i send an instance of a model to a view constructor, they are linked, if i change the model in my view, the outside one will be affected the same way. I guess sometime we just send a pointer and not a copy of the instance to the view.
More specific with some code;
A = new UserModel();
B = new UserModel();
var Data = A.get('info'); //where info = {some: "thing"};
Data.some = 'other';
B.set('info', Data); //A.get('info') == B.get('info')
Because i got the object info and not only the attributes separately (i tested it and there is no repercution between the values this way).
So my question is, are we always using pointers with objects in javascript ? Is it specific to backbone ? I would like to understand what is behind this behavior.
Thanks.
Objects and Arrays are passed or assigned as references in javascript, not copies. If you want a copy of an object or an array, you have to explicity make a copy.
Simpler types such as numbers, boolean are copied when assigned or passed.
Strings are a bit of special case. They are passed as references, but since strings are immutable (can't be changed), you can't really use a string reference for anything because any attempt to modify the string creates a new string.
A couple examples:
// arrays assigned by reference
var a = [1,2,3];
var b = a;
a[0] = 0;
alert(b[0]); // alerts 0 because b and a are the same array
// objects assigned by reference
var c = {greeting: "hello"};
var d = c;
c.greeting = "bye";
alert(d.greeting); // alerts "bye" because c and d are the same object
// numbers assigned as copies
var e = 3.414;
var f = e;
e = 999;
alert(f); // alerts 3.414 because f is its own copy of the original number
// make a copy of an array
var g = [1,2,3];
var h = g.slice(0); // h is now a copy
h[0] = 9;
alert(g); // shows [1,2,3]
alert(h); // shows [9,2,3]
The same is true for passing arguments to a function or returning values from a function. Unless an explicit copy is created, arrays and objects are passed or returned by reference.
A shallow copy of an array can be made with the .slice() method.
var arr1 = [1,2,3];
var arr2 = arr1.slice(0); // make independent copy of first array
A shallow copy of an object can be made by copying each property from the original object to a new object.
Deep copies involve testing the type of each item being copied and recursing on the object if it is an object or array so nested objects and arrays are copied too.
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Copying array by value in javascript
i have a funny problem with javascript. i copy an array variable to make modifications on the copy only, then splice the copy to delete an element. however the original array variable is affected by the splice - as if the copy was a 'copy by reference':
window.onload = function() {
var initial_variable = ['first', 'second', 'third'];
var copy_initial_variable = initial_variable;
copy_initial_variable.splice(0, 1);
alert('initial variable - ' + initial_variable);
};
//output: initial variable - second,third
firstly, is this intentional behaviour for javascript or is it a bug?
and secondly, how can i make a copy of an array and delete an element in the copy but not in the original?
one thing which makes me think that the above may be a javascript bug is that this behaviour only happens with arrays and not with integers. for example:
window.onload = function() {
var initial_variable = 1;
var copy_initial_variable = initial_variable;
copy_initial_variable = 2;
alert('initial variable - ' + initial_variable);
};
//output: initial variable - 1
if the behaviour were consistent then this ought to output 2 since the assignment would presumably be by reference?
This is in no way a bug, but a very common misunderstanding. Let's see what happens when I say
var a = b;
Integers and other javascript primitives, like floats and booleans, are "assigned by value".
Which means that whatever value b has is going to be copied to a. To the computer, it means having the part of memory that b references copied to the memory that a references. That's the behavior you were expecting.
When arrays and other objects (and "descendants" of a new Object() call) are used like that, there is a copy by reference. Meaning that the value of a now references the value of b, the memory that b references isn't copied or modified. Thus, when writing
a = [1,2,3];
b = a;
b and a become interchangeable. They're referencing the same memory address. To achieve what you're trying to do, use
var copy_initial_variable = initial_variable.slice(0);
Read Does JavaScript pass by reference? for more information.
In first case you are working with arrays, which are passed by reference. And in second case you are working with prime types which are passed by value. In first case you should copy initial array (e.g. with initial_variable.slice(0)). Try something like
window.onload = function() {
var initial_variable = ['first', 'second', 'third'];
var copy_initial_variable = initial_variable.slice(0); //returns new array!!!!
copy_initial_variable.splice(0, 1);
alert('initial variable - ' + initial_variable);
};
The problem isn't in how splice behaves, but the fact that initial_variable and copy_initial_variable reference the same array.
alert (copy_initial_variable === initial_variable);
In JavaScript there are two types of values: primitive values, like numbers and booleans, and objects, including arrays. Variables hold primitive values, but they hold references to objects. "Copying" primitive values works as you expect, a new primitive value is created so that changing the copy variable will not change the original variable. But "copying" an object actually copies the reference pointing to that object, it doesn't create a new object.
It is not a JavaScript bug, this is the intended behavior.
Today I came across this problem in javascript and do not know why it happens.
var a = {
prop: {
bool: true
}
};
console.log(a.prop.bool); // logs true
var b = a;
b.prop.bool = false;
console.log(a.prop.bool); // logs false ¿?
The expression { prop: ... } expression is evaluated once to create one object.
a and b both are references to that single object.
See What's the difference between passing by reference vs. passing by value? and http://en.wikipedia.org/wiki/Reference_(computer_science)
References are widely used in programming, especially to efficiently pass large or mutable data as arguments to procedures, or to share such data among various uses.
EDIT
clone from underscore does a shallow copy.
Create a shallow-copied clone of the object. Any nested objects or arrays will be copied by reference, not duplicated.
To create a deep copy, the easiest way is probably to serialize and deserialize. This will do weird things if a has reference cycles though.
var b = JSON.parse(JSON.stringify(a));
You've created a reference to the same object. When you do this, any changes of variable b will affect the object stored in variable a.
You will need to do a 'clone' of the object to change it so you have two objects instead of one with two references.
when you assign b to a the assignment is by reference meaning b references the same location in memory as a so when b is updated and you observe a it looks like a is also updated.