Object and Arrays - Reference vs Copy
syntax - Reference Array Elements in JavaScript - Stack Overflow
javascript return reference to array item - Stack Overflow
Referencing Arrays in Javascript - Stack Overflow
Hi all,
I was reading up on this topic, as I am learning JS and what I took away from it, at least initially is that:
When you reference an array or object, if you create a new variable and make any changes to the property of an object or an item inside an array, not only will that new variable see the changes, but the object or array will also be changed since it is referenced to the original object or array. To avoid this, you need to make a copy of the object or array and then change the value of the property inside of the object or the item within an array. Does this sound correct?
You could define a getter that acts as a reference to the live variable:
var myArray = Object.defineProperty([0,1], 2, {
get() { return x },
enumerable: true,
configurable: true
});
var x = 2;
console.log(myArray);
x = 3;
console.log(myArray);
Of course, this is a horrible thing to do to an array, and will probably incur heavy performance penalties in every place where the array is used. So: don't do this. Just assign to myArray[2] instead of x in every place, or use a getter/setter function pair instead of the x variable that does this.
function setX(v) { myArray[2] = v; }
var myArray = [0,1,2];
setX(2);
console.log(myArray);
setX(3);
console.log(myArray);
You could put your value in an object.
var x = {
value: 2
}
var myArray = [0,1,x];
console.log(myArray[2].value); // 2
x.value = 3;
console.log(myArray[2].value); // 3
In this case you are always pointing to the same object, the content of which can change at any time.
I tried to use
Array.filter()function, but it returns a new array instead of a reference to the original array. which I can not use to mutate the original array.
It returns a new array, but the array's entries are still references to the same objects. So filter is just fine for this.
var filteredUsers = users.filter(function(entry) { return entry.id === 2; });
var item = filteredUsers[0];
item.name = "user2 name updated";
console.log(users[1].name) // "user2 name updated"
The array contains references to the objects, not copies of them. When we do item = users[1], or use filter to get a new array containing a subset of the objects, we get a copy of the object reference, and so the variable now refers to the same object, like this:
+ββββββββββ+
usersββββββββββ>| (array) |
+ββββββββββ+ +βββββββββββββββ+
| 0 |ββββββββββ>| (object) |
| | +βββββββββββββββ+
| | | id: 1 |
| | | name: "name1" |
| | +βββββββββββββββ+
| 1 |ββ+
| | |
| | | +βββββββββββββββ+
| | +βββ+β+β>| (object) |
+ββββββββββ+ / / +βββββββββββββββ+
| | | id: 2 |
+ββββββββββ+ | | | name: "name2" |
filteredUsersββ>| (array) | | | +βββββββββββββββ+
+ββββββββββ+ | |
| 0 |βββββ+ |
+ββββββββββ+ |
|
itemβββββββββββββββββββββββββββββββ+
Changing the object changes the object, and those changes are visible regardless of which reference to the object you use to look at its properties.
Now if you had an array of primitives:
var a = [1, 2, 3, 4, 5];
...then of course, you can't use the approach above because they aren't objects. In that case, you'd use indexOf to find the index:
var index = a.indexOf(3); // Find the first entry === 3
...and then modify the entry
a[index] = 42;
This also applies to strings (provided they're nice normal string primitives, not things you created via new String(), which there's virtually never a reason to do).
To do it similarly to the accepted answer, but a bit more succinctly, let us use Array.find, like so:
var item = users.find(u => u.id === 2)
item.name = "user2 name updated"
console.log(users[1].name) // "user2 name updated"
Explanations are very similar to what has been provided in the accepted answer.
Your code is creating new empty array, instead you can empty existing array with length = 0
var myArray = [2, 3, 4, 5];
function doStuff(arr) {
arr.length = 0;
};
doStuff(myArray);
console.log(myArray)
Run code snippetEdit code snippet Hide Results Copy to answer Expand
Arrays are passed by reference in JavaScript. So, in your doStuff and changeSecondIndex functions, the arr parameter contains a reference to myArray.
In changeSecondIndex, you're using that reference to access and update a property of the array. That works fine, as you can see. But in doStuff, what's actually happening is that you are setting arr to a new array. What that does is remove the fact that arr was a reference to myArray and sets it to a new blank array. That's why myArray is not modified.
Put an object into the array instead:
var name = {};
name.title = "foo";
var array = [];
array["reference"] = name;
name.title = "bar";
// now returns "bar"
array["reference"].title;
You can't.
JavaScript always pass by value. And everything is an object; var stores the pointer, hence it's pass by pointer's value.
If your name = "bar" is supposed to be inside a function, you'll need to pass in the whole array instead. The function will then need to change it using array["reference"] = "bar".
Btw, [] is an array literal. {} is an object literal.
That array["reference"] works because an Array is also an object, but array is meant to be accessed by 0-based index. You probably want to use {} instead.
And foo["bar"] is equivalent to foo.bar. The longer syntax is more useful if the key can be dynamic, e.g., foo[bar], not at all the same with foo.bar (or if you want to use a minimizer like Google's Closure Compiler).
First thing is arrays are always passed as reference in javascript.
Now coming to your question, when an array is passed to a function the argument variable of that function will hold that reference, in your case it's arr argument. If you mutate arr it will mutate original array as it is referring to original array but if you just assign some other value or reference to arr it will no longer hold reference to that original array and any changes to new reference won't have any effect on that array.
JavaScript is pass by value. However, when passing an object as a parameter, the value is the reference.
An array is an object. When modifying the property of an object, the change will be reflected even outside of the function scope. Thus, modifying one item (e.g, a property of the array) produces said effect. However, replacing the object will only replace the value to which said reference points toward, thus the change will only be reflected within the scope of the function.
It looks like you are confusing JavaScript array objects with the fact that all objects are associative arrays. Note that normal objects (e.g. the "Fruit" object you allude to) do not have an intrinsic ordering of properties (keys) whereas Array objects do (due to the natural ordering of integral indices). Essentially, an Array is just an object with a special "length" property that stores the last integer index (starting from zero) plus one.
Any object's properties will be iterated in arbitrary (e.g. random) order:
var obj = {a:'Aye', b:'Bee', c:'See', d:'Dee'};
for (var prop in obj) {
alert(prop + '=' + obj[prop]); // No order is guaranteed.
}
Strictly speaking, even arrays are not guaranteed by the specification to iterate in natural order using a for-in loop; however, most JavaScript interpreters do so anyway. (Notably, IE8 iterates in the order that indices were assigned, not natural order.) This is why you should always iterate arrays using indices in a plain "for" loop.
var arr = ['a', 'b', 'c', 'd', 'e', 'f'];
for (var i=0; i<arr.length; i++) { // i = [0 .. length-1]
alert(arr + '=' + arr[i]); // Explicitly order as 'a', 'b', 'c'...
}
These differences mean that regardless of how your "Fruit" object is defined there is no reliable way to ensure a strict ordering of keys (e.g. "Banana", "Apple", "Color", "Size", etc.) unless you retain your own ordering separately.
I'm a little confused, because you seem to have answered your own question. I also don't know how you have your array(s) set up. But if you take a look at this example, you can see it working here:
http://jsfiddle.net/uyNnH/
This assumes that the top level array contains your fruit types and second level array contains each fruit type's properties.
Update:
From Mozilla and others:
In JavaScript 1.0, you can refer to an object's properties by their property name or by their ordinal index. In JavaScript 1.1 or later, however, if you initially define a property by its name, you must always refer to it by its name, and if you initially define a property by an index, you must always refer to it by its index.
So the issue is that you declare an associative array, instead of an indexed/ordinal-based one. The only solution I can think of is using a (ugly) for loop. Here's some un-tested pseudo-code:
function getItemByIndex(index, array) {
var counter = 0;
for (item in array)
{
if (counter == index)
{
return item;
}
counter++;
}
}