Change array variable inside Javascript object literals - javascript

An example of below is available here: http://jsfiddle.net/valgaze/se9bmx7t/
Big question: Why does clearing an array "break" the relationship between an array and that array's reference in an object literal in Javascript?
Imagine we have an array stored in a variable and we have object literal with a reference to that array as one of the properties of the object. When we use any of the typical array methods (push, pop, shift, etc) on the array, the object literal gets updated with the result. And similarly if we update the array by accessing it from the object literal then the array variable is updated.
Ex. Updating the object updates the array (and vice versa)
var myArray = ["item1", "item2", "item3"];
var myObject = {key1:"value1", key2:myArray}
//Array is updated, so object is updated
myArray.push("item4"); //Update the array
console.log(myObject.key2); //Object's array updated with new pushed value
//Object is updated, so array is updated
myObject.key2.push("item5"); //myArray is updated with the item5
console.log(myArray); //Array updated with item5
Question: Why does "clearing" the array break the binding/coupling on the array reference in the object?
//[...] continued from first block above
myArray = ["muahahah, everything is wiped out"];
console.log("myArray", myArray); //Returns ["muahahah, everything is wiped out"]
console.log("myObject.key2", myObject.key2); //Returns the original items 1-5
//If we clear out the array via the object, the array does get updated
myObject.key2 = ["cleared the array from object"];
console.log("myArray", myArray); //returns ["cleared array"]
console.log("myObject.key2", myObject.key2); //returns ["cleared array"]
There must be something going on with manipulating an array like this: myArray = ["wiped values"];

You're not "clearing" the array, you're assigning a new value to your variable. The original array still exists (as a reference inside the other object), but now myArray points to a different array reference.

Related

Why using push or any array method modifies the original array but assigning it to something else doesn't?

I don't understand why assigning the array to a new value doesn't affect the new array.
I know that "push" modifies the original array, splice also, and filter or slice doesn't, this is not my question. my question is that why assigning doesn't.
i have looked through old questions answers saying it is passed by reference but again if it is passed by reference then changing it's value should affect the reference also.
const modify = (someArray) => {
// modified my array
someArray.push(1)
// modified my original array
someArray[0] = 'A'
// didn't modify my array and I want to know why.
someArray = ['whatever']
}
let myArray = ['a', 'b']
modify(myArray)
console.log(myArray) //  ["A", "b", 1]
In Javascript (and Java or C#) everything is by default passed by value!
The important is to know, what the value is. This line let myArray = ['a', 'b'] creates new array in memory and put the reference to it into myArray. Now, the value of myArray is the reference to the memory where ['a', 'b'] reside.
When you pass it to modify function, the value - which is the reference - is copied from myArray to someArray. It means someArray can access the same memory segment of the same array, therefore change the values inside that array, but you cannot change the value of myArray (which is the reference to that array) from someArray.
As I've described this to beginners many times, I've found that it's best to think of Objects in Javascript as being passed and assigned as a pointer (as in the way pointers work in C/C++). So, when you do this:
let a = [1,2,3];
let b = a;
You now have two variables that each have a pointer to the same [1,2,3] array. I find it works best to think about the array existing on its own and you now have two variables that each point at that array. When you assign b = a, it doesn't make a copy of the data, it just points b at the same data that a was pointing at.
If you modify that array with something like a.push(4) or assigning like a[0] = 9, then the one and only one array that both a and b point to has been modified. So, whether you access that array from a or from b, you will see the change because both variables point at the same physical array object.
But, if you reassign some other array to b like this:
b = [9,8,7];
You've just taken a new array and put a pointer to it in b. The other variable a still points to the same original array that is used to. It hasn't been changed in any way.
When you pass an array as an argument like you are doing in your modify() function, the function argument in the function is just like the b variable in the above example. It's just another variable that points at the same array. If you modify the array itself, then both variables will point at the same modified array. But, if you reassign the argument variable to now point at some other array, only that variable is affected.
['a', 'b'] is an array. myArray is a variable that refers to that array. someArray is a variable local to modify function that will take the value of myArray (i.e. the reference to your array; so both myArray and someArray refer to the same array). As you noted, someArray.push(1) and someArray[0] = 'A' both modify the array referred to by someArray. someArray = ["whatever"] will change the reference of someArray to the new array ['whatever'], but myArray still refers to the old array. At the end of the function, someArray variable disappears (and ['whatever'] is forgotten, since nothing refers to it any more).
There is no way in JavaScript to change the reference of the variable passed into a function (as e.g. C++ can); you can only manipulate what received reference points to.

JavaScript, Memory: Elements in Array

I have a short question, just out of curiosity.
Let's say I have an object which has an array as a property this.arr = ["one", "two", "three", ...], and I populate this array with n elements.
What will happen to all these elements if I run this.arr = [] . Are they deleted, kept in memory, leaked?
Thanks!
this.arr = [] will create a new empty array and assign it to the arr property. If there is no more reference to the previous array in the program, it will be garbage collected eventually (automatically destroyed by the JS engine). But if there is still a reference to it somewhere, it will still exist.
this.arr = [1, 2, 3, 4];
var backup = this.arr;
this.arr = [];
// backup still points to the array, so it won't be destroyed
If you just want to delete an array as you won't use it anymore, you could do this.arr = null instead.
In JS, there is no such thing as "memory leaks". You can, however, forget to get rid of an object you don't need anymore. And if that object has references to other objects which in term have references to other objects, than not a single object of the tree will get destroyed.
Most of the time, if you use temporary variables, you won't need to worry about it.
They are deleted. As a matter of fact this is a fast way to empty an array.
It would be deleted. If you assign the value of this.arr to another variable, the array would be reusable, but the other variable would have different memory address, but the address, you stored the original variable would be emptied.
They will be deleted, If the string objects are no longer referenced by anything. The string objects are therefor eligible for the garbage collection to delete/release these objects.

Empty Array in javascript

I created an object which contains an array.
I noticed that when I dont enter any values into the array, it still has one - its size,
So how can I check if the array is actually empty?
Here's how I'm creating the array:
array = { text:[10] }
The size of the array is not an array entry (aka array "element"). It is a property, length, but it's not an entry. An empty array is exactly that: empty.
The code you posted in a comment:
array = { text:[10] }
does not create an empty array. It creates an array of length 1 with the entry 10 in it.
If you want to create an empty array with a specific length, you can't do that in a single statement with an array literal ([]). You have two ways you can do it:
Using an array literal and assigning to length:
var a = [];
a.length = 10;
or using new Array:
var a = new Array(10);
But there's virtually never any reason, in JavaScript, to predefine the length of the array, because standard JavaScript arrays aren't really arrays at all. It does make sense with the new typed arrays (Uint32Array and such), and to do it you have to use the array constructor (new Uint32Array(10)).

Weird issue with slice() when copying an array

I have an "empty" array that will be populated with data later in the code. But before it reaches that stage there's a section where the default content is copied to a temporary array, so the original can be changed and later receive the relevant data that was stored in the copy.
The problem is when I use slice and delete the section in the original array, the temporary one is affected as well.
var array1 = [["text", [[[1,2],[3,4],[5,6]]], 0]];
var array2 = array1[0].slice(0);
//alert(array2[1][0]) // Output: 1,2,3,4,5,6
array1[0][1][0] = new Array();
//alert(array2[1][0]) // Output:
http://jsfiddle.net/Mbv6j/4/
I can use a workaround to copy each section of the array separately rather than all at once, but I still would like to understand why this is happening.
This is expected behaviour. Have a look at the documentation.
You only get a shallow copy of the original array:
The slice() method returns a shallow copy of a portion of an array into a new array object.
For the arrays, object references are stored, so just the references get copied. For the String you will not observe this behaviour.
For object references (and not the actual object), slice copies object references into the new array. Both the original and new array refer to the same object. If a referenced object changes, the changes are visible to both the new and original arrays.
For strings and numbers (not String and Number objects), slice copies strings and numbers into the new array. Changes to the string or number in one array does not affect the other array.
Taken from here:
For object references (and not the actual object), slice copies object
references into the new array. Both the original and new array refer
to the same object. If a referenced object changes, the changes are
visible to both the new and original arrays.
My guess is that since your array contains arrays of arrays, they are probably being represented as object references; thus, slice is copying the references, not the objects. It only does a shallow copy, not a deep copy. If the items in your array weren't objects, you wouldn't encounter this problem.

push associative array error?

I have to push elements in an associative array from another array after some processing and I'm doing something this:
for(var i in this.aNames) {
var a = this.aNames[i];
// some processing on a
aList[i] = a;
aList.push(i);
}
But it's not giving me the proper array.
EDIT :
Here aNames is an associative array like this
'1232':'asdasdasd',
'6578':'dasdasdas'
...... and so on of about 100 elements.
I'm using for here as I want to do some changes in every element of the array.
Then I'm displaying the result array on the page but it's showing the key value together with the array data.
I.e. it should only display asdasdasd or asdasdasd but it's displaying keys too, like 1232 asdasdasd 6578 dasdasdas.
There are multiple things which may go wrong...
Primarily, make sure that this is pointing to the correct context and that this.aNames is actually returning a complex object (associative array).
Also, what's aList? Is it an array? If it is, push should append your array with the key of the current member (the member's name).
If you want to append the values of the members on your source object, you need to do something like this:
var obj = {name: 'dreas'},
arr = []; // arr is an array
arr.push(obj["name"]); // arr now contains a single element, 'dreas'
In your for..in construct, you are both adding elements to an alleged array (aList) with push but also creating new members on your array (with the subscript notation, aList[i] = "asd" since i in this case (for..in iteration) refers to the member's name).
So, what you need to do is decide if you want to add elements to an array or members to an object, not both.
If you just want to clone an array, use a for loop. If on the other hand you want to clone an object, it's not that trivial because members can also be complex objects containing their own members, and simply doing arr[i] = obj.member will only copy a pointer to arr[i] if member is a complext object, not a value type.
Just to make sure my terminology is understandable:
var anObject = {name: "dreas"},
anArray = [1,2,3];
anObject["name"] <= member (results in "dreas")
anArray[1] <= element (results in 2)

Categories