What you should know about JavaScript arrays

Lukas Gamper, uSystems GmbH

Outline

  • Array functions
  • Remove duplicates
  • Arrays with holes

Spread operator (ES2015)


const numbers = [1, 2, 3]
const numbersCopy = [...numbers]
console.log(numbersCopy) // [1, 2, 3]

const otherNumbers = [4, 5, 6]
const numbersConcatenated = [...numbers, ...otherNumbers]
console.log(numbersConcatenated) // [1, 2, 3, 4, 5, 6]

Uses iterator protocol


const matches = document​.query​SelectorAll(); // NodeList
const array = [...matches] // Array

not supported by ie11

reduce (ES5)


const numbers = [37, 12, 28, 4, 9]
const total = numbers.reduce((sum, n) => sum + n, 0)
console.log(total) // 90

function reduce(array, reducer, inital) {
    let result = inital;
    for (let i = 0; i < array.length; ++i) {
        result = reducer(result, array[i]);
    }
    return result;
}

reduce can be seen as:

supported by all browsers

reduce (ES5)


const numbers = [1, 2, 3, 6, 7]
const cumSum = numbers.reduce(
    (arr, item, index) => [...arr, (index ? arr[index - 1] : 0) + item],
    [0]
)
console.log(cumSum); // [1, 3, 6, 12, 19]

supported by all browsers

reduce (ES5)


const sports = ['football', 'archery', 'judo']
const counts = sports.reduce(
    (obj, item) => (obj[item] = 0, obj),
    {}
)
console.log(counts); // { football: 0, archery: 0, judo: 0 }

supported by all browsers

reduce (ES5)


const map = (arr, fn) => {
  return arr.reduce((mappedArr, element) => {
    return [...mappedArr, fn(element)]
  }, [])
}

console.log(map([1, 2, 3, 4], n => n + 1)) // [2, 3, 4, 5]

const filter = (arr, fn) => {
  return arr.reduce((filteredArr, element) => {
    return fn(element) ? [...filteredArr, element] : [...filteredArr]
  }, [])
}

console.log(filter([1, 2, 3, 4, 5, 6], n => n % 2 === 0)) // [1, 3, 5]

supported by all browsers

includes (ES2016)


const sports = ['football', 'archery', 'judo']
const hasFootball = sports.includes('football')
console.log(hasFootball) // true

not supported by ie11

find / findIndex (ES5)


const users = [
  { id: 'af35', name: 'john' },
  { id: '6gbe', name: 'mary' },
  { id: '932j', name: 'gary' },
]

const user = users.find(user => user.id === '6gbe')
console.log(user) // { id: '6gbe', name: 'mary' }

const user = users.findIndex(user => user.id === '6gbe')
console.log(user) // 1

not supported by ie11

flat (ES2019)


const numbers = [1, 2, [3, 4, [5, [6, 7]], [[[[8]]]]]]

const numbersflattenOnce = numbers.flat()
console.log(numbersflattenOnce) // [1, 2, 3, 4, [5, [6, 7]], [[[8]]]]]

const numbersflattenTwice = numbers.flat(2)
console.log(numbersflattenTwice) // [1, 2, 3, 4, 5, [6, 7], [[8]]]

const numbersFlattenInfinity = numbers.flat(Infinity)
console.log(numbersFlattenInfinity) // [1, 2, 3, 4, 5, 6, 7, 8]

not supported by ie11 and edge

flatMap (ES2019)

const sentences = [
  'This is a sentence',
  'This is another sentence',
  'I can\'t find any original phrases',
]

const allWords = sentences.flatMap(sentence => sentence.split(' '))
console.log(allWords) // ['This', 'is', 'a', 'sentence', 'This', 'is',
                      //  'another', 'sentence', 'I', 'can't', 'find', 
                      //  'any', 'original', 'phrases']

not supported by ie11 and edge

flatMap is identical to a map followed by a flat of depth 1

Remove duplicates


const array = ['🍻', 1, 2, '🍻', '🍻', 3];

const uniqueArray = array.reduce(
    (unique, item) => unique.includes(item) 
        ? unique 
        : [...unique, item], 
    []
);

using reduce

Remove duplicates


const array = ['🍻', 1, 2, '🍻', '🍻', 3];

const uniqueArray = array.filter(
    (item, index) => array.indexOf(item) === index
);

using filter

item index indexOf Condition
🍻 0 0 true
1 1 1 true
2 2 2 true
🍻 3 0 false
🍻 4 0 false
3 5 5 true

Remove duplicates


const array = ['🍻', 1, 2, '🍻', '🍻', 3];

const uniqueArray = [...new Set(array)];

using Set

  • Set is unique
  • Set stores elements in insertion order
    order is preserved

Arrays with holes


> [ 'a',, 'b' ]
    ['a', empty, 'b']

This is essentially equivalent to the object

{
    0: 'a',
    2: 'b',
    length: 3
}

> [ 'a',, 'b' ].length
    3

Arrays with holes


> [ 'a', 'b', ]
    [ 'a', 'b' ]
> [ 'a', 'b', ].length
    2

> [ 'a', 'b',, ]
    [ 'a', 'b', empty ]
> [ 'a', 'b',, ].length
    3

JavaScript ignores a trailing comma

but only one

Arrays with holes


> var a = [ 'a', 'b' ];
> a.length = 3;
> a
    [ 'a', 'b', empty ]

The length of an array is mutable

Arrays with holes

[...[ 'a',, 'b' ]]
    ['a', undefined, 'b']
Array.from([ 'a',, 'b' ])
    ['a', undefined, 'b']

copy array

> [ 'a',, 'b' ].reduce((array, item) => [...array, item], [])
    ['a', 'b']
[ 'a',, 'b' ].map(a => a)
    ['a', empty, 'b']
[ 'a',, 'b' ].slice()
    ['a', empty, 'b']
[].concat([ 'a',, 'b' ])
    ['a', empty, 'b']

Slice and concat preserve holes

Spread operator and Array.from use the iterator protocol

Map preserves holes

Reduce removes holes

Arrays with holes

 > [ 'a',, 'b' ].every(item => item.length === 1)
    true

array methods

> [ 'a',, 'b' ].jon('-')
    'a--b'
> [ 'a',, 'b' ].filter(item => true)
    [ 'a', 'b' ]
> [ 'a',, 'b' ].forEach((item, index) => `${item}.${index}`)
    ['0.a', '2.b']

forEach() skips holes

every() skips holdes (like some() )

filter eliminates holes

join() converts holes to empty strings

> [ 'a',, 'b' ].map((item, index) => `${item}.${index}`)
    [ '0.a', , '2.b' ]

map() skips, but preserves holes

Thanks

What you should know about JavaScript arrays

By gamperl

What you should know about JavaScript arrays

  • 219