Web Technologies

JavaScript

Массивы

Массив (array) представляет собой форму организации упорядоченного набора данных.
Массивы в JavaScript — это объекты особого вида, имеющие среди свойств числовые индексы и наследующие методы от Array.prototype.
В верности сказанного можно убедиться, запустив следующий код:

const ads = ['first', 'second', 'third']; for (let key in ads) { console.log(key + ': ' + ads[key]) }; console.log(typeof ads); console.log(Object.getPrototypeOf(ads) == Array.prototype);

Перемешивание массива в случайном порядке.

Определив следующую функцию как метод Array.prototype, мы сможем вызывать её на любом массиве:

function shuffle(array){ const random=[], copy = array.slice(); while(copy.length){ const r = Math.floor(Math.random()*copy.length); random.push(copy[r]); copy.splice(r, 1) }; return random }; /* пример: */ console.log(shuffle([1, 2, 3, 4, 5, 6]))

Сравнение массивов

Массивы представляют собой частный случай объектов; тождество значений всех свойств объектов не позволяет считать объекты тождественными — объект не определяется однозначно своими свойствами; точно так же массив не определяется свими элементами и их порядком. Поэтому следующий код выдаёт false: console.log([1, 2]==[1, 2]). Для установления эквивалентности массивов можно использовать следующую функцию:

function equal(first, second, compare) { return first.length == second.length && first.every((element, index) => compare(element, second[index])) }; console.log(equal([1, 2], [1, 3], function compare(a, b) { return a == b })); console.log(equal([1, [2, 3]], [1, [2, 3]], function compare(a, b) { if (Array.isArray(a) && Array.isArray(b)) { return equal(a, b, compare) } else { return a == b } }))

Функция equal принимает два массива для сравнения и функцию сравнения элементов. Для работы с одномерными массивами, состоящими из примитивов, в качестве третьего аргумента достаточно использовать функцию, возвращающую true в случае тождества примитивов и false в противном случае (первый пример в коде выше). Для сравнения многомерных массивов (второй вызов функции equal в коде) и вообще массивов, элементами которых являются объекты, в качестве compare необходимо использовать функцию, осуществляющую глубокое сравнение (см. здесь; приведённую функцию deepEqual можно также непосредственно использовать для сравнения массивов).

Также можно использовать универсальный способ сравнения объектов:

console.log([1, 2] == [1, 2]); function equal(first, second){ return JSON.stringify(first) == JSON.stringify(second) }; console.log(equal([1, 2], [1, 2]))

В некоторых случаях нам может потребоваться выяснить, состоят ли массивы из одних и тех же элементов, пренебрегая порядком элементов и числом вхождений:

function equal(first, second, comparer) { if (!comparer) { comparer = { equals(a, b) { return a == b } }; }; let set = Array.from(second), count = first.length, count2 = second.length; for (let i = 0; i < count; i++) { let item = first[i]; if (!second.some(el => comparer.equals(el, item))) { return false } else { set = set.filter(el => !comparer.equals(el, item)) } }; return set.length ? false : true }; console.log(equal([1, 2, 3], [3, 2, 1, 2]));

В этом коде в качестве третьего аргумента в дефолтном варианте выбирается функция, устанавливающая тождество (==) переданных ей значений.

Копирование массива

Простое объявление новой переменной, ссылающейся на существующий объект не приводит к созданию нового объекта.
Для того, чтобы создать новый массив, идентичный данному, но меняющийся независимо от данного, можно использовать один из способов, продемонстрированных в следующем листинге:

const array = [1, 2, 3], array_1 = array, /*Новый массив не создан — переменная array_1 ссылается на прежний массив.*/ array_2 = array.map(e => e), array_3 = array.concat(), array_4 = Array.from(array), array_5 = array.slice(), array_6 = array.filter(el => true), [...array_7] = array, array_8 = JSON.parse(JSON.stringify(array)); array_2[0] = array_3[0] = array_4[0] = array_5[0] = array_6[0] = array_7[0] = array_8[0] = 100; console.log(array == array_1); console.log(array == array_2); console.log(array == array_3); console.log(array == array_4); console.log(array == array_5); console.log(array == array_6); console.log(array == array_7); console.log(array == array_8); console.log(array[0]) /* Остался прежним. */

Все перечисленные способы (кроме последнего — представленного в строке 9 — представляющего собой реализацию универсального метода копирования объектов) идеально подходят лишь для копирования одномерного массива.
Для построения копии многомерного массива любого уровня вложенности применим следующую функцию:

function copy(array){ return array.map(element => { if(Array.isArray(element)){ return copy(element) } else{ return element } }) }; const old = [1, [[2, 3], 4]]; const young = copy(old); young[1][0][1]=5; console.log(old); console.log(young)

Многомерные массивы.

Следующий код позволяет найти общее число элементов принадлежащих как самому многомерному массиву, так и входящим в него массивам:

function countElems(array) { return array.reduce((length, el) => { return Array.isArray(el) ? length += countElems(el) : ++length }, 0) }; console.log(countElems([1, [[2]], [3, [4], [[[[[5, 6]]]]]]]))

Тот же результат может быть получен применением метода flat:

const array = [1, [[2]], [3, [4], [[[[[5, 6]]]]]]]; console.log(array.flat(Infinity).length)

Транспонирование матрицы (двумерного массива).

function transpone(matrix) { const t_matrix = [], l = matrix[0].length; for (let i = 0; i < l; i++) { t_matrix.push(matrix.map((row) => row[i])); } return t_matrix; }