Quick tip for arrays in JavaScript
Arrays very common and useful data structure to save collections but they have a small catch in JavaScript, they are in truth objects. While this is probably not news to someone that uses JS it may come has a weird surprise to someone that is just starting out.
The reason
JS right now has six primitive types which are string, number, boolean, null, undefined and symbol and, when something doesn’t fit one of those it is assigned as an object, such is the case for arrays and functions.
“An object needs a key and value”
let foo = [1, 2, 3]// Is internally for JS something of the likes oflet foo = {
"0": 1,
"1": 2,
"2": 3,
}// And that is why you can access it withfoo[0]
foo[1]
foo[2]// If object properties/methods could be numbers you could access in this case like sofoo.0
foo.1
foo.2
What does it mean
It may cause you some problems in at least two scenarios, when assigning by reference unknowingly and when using for...in
.
By reference
When creating new objects using already declared ones the new one if changed also mutates (changes the value) of the first object, for example:
let firstObject = {
foo: 1,
}console.log(firstObject) // {foo: 1}let secondObject = firstObjectsecondObject.bar = 2console.log(firstObject) // {bar: 2, foo: 1}
console.log(secondObject) // {bar: 2, foo: 1}
While the primitive types assign by value in case of objects they assign by reference so, the moment you do let secondObject = firstObject
you are in fact saying “whenever secondObject
is changed also change firstObject
”. Since that happen with objects, it will also happen when using it with arrays.
To avoid reference you can use something like this
let firstObject = {
foo: 1
}
let secondObject = {}for (let key in firstObject) {
secondObject[key] = firstObject[key]
}secondObject.bar = 2console.log(firstObject) // {foo: 1}
console.log(secondObject) // {bar: 2, foo: 1}
This works since this secondObject[key] = firstObject[key]
is assigning a primitive type, in this case the number “1". You can also achieve this natively by using an ES6 feature called Object.assign
.
let secondObject = Object.assign({}, firstObject)
“What if I have and object inside an object?” — Well, in this scenario both the example with the for
and the one with Object.assign
will fail to assign by value any nested objects in your object, I would recommended you use _.merge
from lodash or $.extend
from jquery. You could also create your own, it might be a good exercise.
For…in
let foo = [1, 2, 3]foo.bar = 4for (let key in foo) {
console.log('--->', key) // this will output "0", "1", "2", "bar"
}
While you might before expect that for...in
would only run once it does in fact loop four times before exiting since in actuality we have 4 properties and not 1, three from the indexes of the array and one from our property bar
.
Avoid assigning arrays and objects to the same variable since they are internally the same surprises like this can happen and take some time to debug, specially for newcomers.
Conclusion
Hopefully this helped you to learn a bit more of how objects and arrays work in JS and it will save you precious debugging time (or the no need for it at all).
Article 13 of 30, part of a project for publishing an article at least once a week, from idle thoughts to tutorials. Leave a comment, follow me on Diogo Spínola and then go back to your brilliant project!