Indexed collections

Переклад цієї статті ще не завершено. Будь ласка, допоможіть перекласти цю статтю з англійської мови

У цьому розділ представлено набір даних, упорядкованих за значенням індексу. Це включає масиви та подібні до масиву конструкції, такі як об'єкти Array та TypedArray .

Об'єкт Array

Масив - це упорядкований набір значень, на який ви посилаєтесь з ім'ям та індексом.

Наприклад, розглянемо масив під назвою emp, який містить імена працівників, індексовані їх числовим номером співробітника. Так emp[1] буде працівником номер один, emp[2] працівником номером два, тощо.

У JavaScript немає явного типу даних масиву. Однак ви можете використовувати заздалегідь заданий об’єкт Array та його методи для роботи з масивами у ваших програмах. Об'єкт Array має методи маніпулювання масивами різними способами, такими як з'єднання(joining), реверсування(reversing) та сортування. Він має властивість визначати довжину масиву та інші властивості для використання з регулярними виразами.

Створення масиву

Наступні операції створюють еквівалентні масиви:

let arr = new Array(element0, element1, ..., elementN)
let arr = Array(element0, element1, ..., elementN)
let arr = [element0, element1, ..., elementN]

element0, element1, ..., elementN - це список значень елементів масиву. Коли ці значення задані, масив ініціалізується з ними як елементами масиву. Властивість довжина (length) масиву встановлюється рівною кількості аргументів.

Синтаксис дужки називається "літералом масиву" або "ініціалізатором масиву". Він коротший, ніж інші форми створення масиву, і тому загалом кращий. Докладніше див. Літерали масиву.

Для створення масиву з ненульовою довжиною, але без будь-яких елементів, може бути використане будь-яке з наведеного нижче:

// This...
let arr = new Array(arrayLength)

// ...буде такий саме масив як цей 
let arr = Array(arrayLength)

// Це має точно такий же ефект 
let arr = []
arr.length = arrayLength

Примітка: У наведеному вище коді, arrayLength повинен бути типу Number. У іншому випадку, буде створений масив з єдиним елементом (з наданим значенням). Виклик arr.length поверне arrayLength, але масив у дійсності убде містити порожні (undefined) елементи. Запуск циклу for...in для масиву не поверне жодного з елементів масиву.

Крім нещодавно означеної змінної, як показано вище, масиви також можуть бути призначені як властивість для нового або існуючого об'єкта:

let obj = {}
// ...
obj.prop = [element0, element1, ..., elementN]

// або
let obj = {prop: [element0, element1, ...., elementN]}

Якщо Ви хочете ініціалізувати масив з єдиним елементом, а цей елемент є Number, ви повинні використовувати синтаксис квадратних дужок. Коли одне значення Number передається конструктору або функції Array(), воно інтерпретується як arrayLength, а не як окремий елемент.

let arr = [42]       // Створює масив тільки з одним елементом:
                     // числом 42.

let arr = Array(42)  // Створює масив без жодного елементу
                     // і довжина масиву arr.length встановлена в 42. 
                     //
                     // Це еквівалентно наступному:
let arr = []
arr.length = 42

Виклик Array(N) призводить до RangeError, якщо N - це не ціле число, тобто дробова частина якого не дорівнює нулю. Наступний приклад ілюструє таку поведінку.

let arr = Array(9.3)   // RangeError: Invalid array length

Якщо ваш код потребує створення масивів з окремими елементами довільного типу даних, безпечніше використовувати літерали масиву. Крім того, спершу створіть порожній масив, перш ніж додати до нього один елемент.

У ES2015 ви можете використовувати статичний метод Array.of для створення масивів з одним елементом.

let wisenArray = Array.of(9.3)   // wisenArray містить тільки один елемент 9.3

Заповнення масиву

Ви можете заповнити масив, призначивши значення його елементам. Наприклад:

let emp = []
emp[0] = 'Casey Jones'
emp[1] = 'Phil Lesh'
emp[2] = 'August West'

Примітка: Якщо ви подасте неціле значення для оператора масиву в наведеному вище коді, буде створено властивість в об'єкті, що представляє масив, замість елемента масиву.

let arr = []
arr[3.4] = 'Oranges'
console.log(arr.length)                 // 0
console.log(arr.hasOwnProperty(3.4))    // true

Ви також можете заповнити масив під час його створення:

let myArray = new Array('Hello', myVar, 3.14159)
// або
let myArray = ['Mango', 'Apple', 'Orange']

Звернення до елементів масиву

Ви звертаєтеся на елементи масиву, використовуючи порядковий номер елемента. Наприклад, припустимо, Ви означуєте такий масив:

let myArray = ['Wind', 'Rain', 'Fire']

Потім Ви звертаєтеся до першого елементу масиву як до myArray[0], а до другого елементу масиву як до myArray[1]. Індекс елементів починається з нуля.

Примітка: Оператор масиву (квадратні дужки) також використовуються для доступу до властивостей масиву. (Масиви також є об'єктами в JavaScript). Наприклад:

let arr = ['one', 'two', 'three']
arr[2]          // three
arr['length']   // 3

Довжина масиву

На рівні реалізації масиви JavaScript фактично зберігають свої елементи як стандартні властивості об'єкта, використовуючи індекс масиву як ім'я властивості.

Властивість length особлива. Вона завжди повертає індекс останнього елемента плюс один. (У наведеному нижче прикладі 'Dusty' індексується на рівні 30, тому cats.length повертає 30 + 1).

Пам'ятайте, що індекси масиву JavaScript базуються на 0: вони починаються з 0, а не 1. Це означає, що властивість length буде на один більше, ніж найвищий індекс, що зберігається в масиві:

let cats = []
cats[30] = ['Dusty']
console.log(cats.length) // 31

Ви також можете записати значення у властивість length .

Введення значення, коротшого за кількість збережених елементів, скорочує масив. Написання 0 спустошує масив повністю:

let cats = ['Dusty', 'Misty', 'Twiggy']
console.log(cats.length)  // 3

cats.length = 2
console.log(cats)  // logs "Dusty, Misty" - Twiggy видалено

cats.length = 0 
console.log(cats)  // logs []; масив cats array - порожній

cats.length = 3 
console.log(cats)  // logs [ <3 пустих елементи> ]

Ітерація з масивами

Поширена операція - це перебір значень масиву, з обробкою кожного елементу. Найпростіший спосіб зробити це наступним чином:

let colors = ['red', 'green', 'blue']
for (let i = 0; i < colors.length; i++) {
  console.log(colors[i])
}

Якщо ви знаєте, що жоден з елементів вашого масиву не повертає false в булевому контексті, наприклад, якщо ваш масив складається з вузлів DOM, Ви можете використовувати більш ефективну ідіому:

let divs = document.getElementsByTagName('div')
for (let i = 0, div; div = divs[i]; i++) {
  /* Process div in some way */
}

Це дозволяє уникнути накладних перевірок довжини масиву та гарантує, що змінна div для додаткової зручності переназначається поточному елементу на кожній ітерації .

Метод  forEach() забезпечує інший спосіб ітерації з масивом:

let colors = ['red', 'green', 'blue']
colors.forEach(function(color) {
  console.log(color)
})
// red
// green
// blue

Крім того, ви можете скоротити код для параметра forEach за допомогою функції стрілок ES2015:

let colors = ['red', 'green', 'blue']
colors.forEach(color => console.log(color))
// red
// green
// blue

Функція, передана forEach , виконується один раз для кожного елемента масиву, при цьому елемент масиву передається як аргумент функції. Не присвоєні значення не перебираються в циклі forEach.

Зауважте, що елементи масиву, опущені при означенні масиву, не перебираються під час ітерації forEach, але пеербираються, коли вручну елемнту було присвоєно undefined:

let array = ['first', 'second', , 'fourth']

array.forEach(function(element) {
  console.log(element)
})
// first
// second
// fourth

if (array[2] === undefined) { 
  console.log('array[2] is undefined')  // true
} 

array = ['first', 'second', undefined, 'fourth']

array.forEach(function(element) {
  console.log(element)
})
// first
// second
// undefined
// fourth

Оскільки елементи JavaScript зберігаються як стандартні властивості об'єкта, не рекомендується проводити повторення через масиви JavaScript, використовуючи цикли for...in , оскільки будуть перебрані як нормальні елементи так і всі властивості масиву.

Методи масивів

Об'єкт Array має наступні методи:

concat() з'єднує два або більше масива і повертає новий масив.

let myArray = new Array('1', '2', '3')
myArray = myArray.concat('a', 'b', 'c')
// myArray тепер такий ["1", "2", "3", "a", "b", "c"]

join(delimiter = ',') об'єднує всі елементи масиву в рядок.

let myArray = new Array('Wind', 'Rain', 'Fire')
let list = myArray.join(' - ') // list є "Wind - Rain - Fire"

push() додає один або більше елементів в кінець масиву і повертає отриману довжину length масиву.

let myArray = new Array('1', '2')
myArray.push('3')  // myArray тепер ["1", "2", "3"]

pop() видаляє останній елемент з масиву і повертає цей елемент.

let myArray = new Array('1', '2', '3')
let last = myArray.pop()
// myArray тепер ["1", "2"], last = "3"

shift() видаляє перший елемент з масиву і повертає цей елемент.

let myArray = new Array('1', '2', '3')
let first = myArray.shift()
// myArray тепер ["2", "3"], first є "1"

unshift()  додає один або більше елементів до передньої частини масиву і повертає нову довжину масиву.

let myArray = new Array('1', '2', '3')
myArray.unshift('4', '5')
// myArray став ["4", "5", "1", "2", "3"]

slice(start_index, upto_index) виймає частину масиву і повертає новий масив.

let myArray = new Array('a', 'b', 'c', 'd', 'e')
myArray = myArray.slice(1, 4)  // починаючи з 1-го вимйає елементи до 4-го
                               // повертає [ "b", "c", "d"]

splice(index, count_to_remove, addElement1, addElement2, ...)  видаляє елементи з масиву та (необов'язково) замінює їх. Він повертає елементи, вилучені з масиву.

let myArray = new Array('1', '2', '3', '4', '5')
myArray.splice(1, 3, 'a', 'b', 'c', 'd')
// myArray тепер ["1", "a", "b", "c", "d", "5"]
// Цей код стартує з першого індексу (or where the "2" was), 
// видаляє 3 елементи, а тоді вставляє всі підряд
// на це місце.

reverse() транспонує масив: перший елемент масиву стає останнім, а останній стає першим. Він повертає посилання на масив.

let myArray = new Array('1', '2', '3')
myArray.reverse()
// транспонований масив myArray = ["3", "2", "1"]

sort() сортує елементи масиву на місці та повертає посилання на масив.

let myArray = new Array('Wind', 'Rain', 'Fire')
myArray.sort()
// відсортований масив myArray = ["Fire", "Rain", "Wind"]

sort() також може скористатися функцією зворотного виклику для визначення порівняння елементів масиву.

Метод sort (та інші нижче), які приймають функцію зворотного виклику, відомі як ітераційні методи, оскільки певним чином вони перебирають весь масив. Кожен з них бере необов'язковий другий аргумент під назвою thisObject. Якщо  thisObject передається, він стає значенням ключового слова this всередині тіла функції зворотного виклику. Якщо це не передбачено, як і в інших випадках, коли функція викликається поза явним контекстом об'єкта, this стосуватиметься глобального об'єкта (window) при використанні функції вказівника зворотного виклику, або undefined при використанні нормальної функції зворотного виклику.

Функція зворотного виклику викликається двома аргументами, які є елементами масиву.

Функція нижче порівнює два значення і повертає одне з трьох значень:

Наприклад, наступне буде сортувати за останньою літерою рядка:

let sortFn = function(a, b) {
  if (a[a.length - 1] < b[b.length - 1]) return -1;
  if (a[a.length - 1] > b[b.length - 1]) return 1;
  if (a[a.length - 1] == b[b.length - 1]) return 0;
}
myArray.sort(sortFn)
// відсортований масив myArray = ["Wind","Fire","Rain"]
  • якщо a за системою сортування менше b , поверне  -1 (або будь-яке від’ємне число)
  • якщо a за системою сортування більше, ніж b , поверне 1 (або будь-яке додатне число)
  • якщо a і b вважати еквівалентними, поверне 0.

indexOf(searchElement[, fromIndex]) шукає масив для searchElement та повертає індекс першого збігу.

let a = ['a', 'b', 'a', 'b', 'a'] 
console.log(a.indexOf('b'))     // пише 1

// Тепер спробуйте ще раз, починаючи з останнього співпадіння
console.log(a.indexOf('b', 2))  // пише 3
console.log(a.indexOf('z'))     // пише -1, оскільки 'z' не було знайдено

lastIndexOf(searchElement[, fromIndex]) працює як indexOf, але починає з кінця і шукає у зворотному порядку.

let a = ['a', 'b', 'c', 'd', 'a', 'b']
console.log(a.lastIndexOf('b'))     // пише 5

// Тепер спробуйте ще раз, починаючи з останнього співпадіння 
console.log(a.lastIndexOf('b', 4))  // пише 1
console.log(a.lastIndexOf('z'))     // пише -1

forEach(callback[, thisObject]) виконує callback на кожному елементі масиву і повертає undefined.

let a = ['a', 'b', 'c']
a.forEach(function(element) { console.log(element) })
// logs each item in turn

map(callback[, thisObject]) повертає новий масив повернутого значення при виконанні зворотного виклику callback на кожному елементі масиву.

let a1 = ['a', 'b', 'c']
let a2 = a1.map(function(item) { return item.toUpperCase() })
console.log(a2) // logs ['A', 'B', 'C']

filter(callback[, thisObject]) повертає новий масив, що містить елементи, для яких callback повернув true.

let a1 = ['a', 10, 'b', 20, 'c', 30]
let a2 = a1.filter(function(item) { return typeof item === 'number'; })
console.log(a2)  // logs [10, 20, 30]

every(callback[, thisObject]) повертає true, якщо callback повертає true для кожного елемента масиву.

function isNumber(value) {
  return typeof value === 'number' 
}
let a1 = [1, 2, 3]
console.log(a1.every(isNumber))  // logs true
let a2 = [1, '2', 3] 
console.log(a2.every(isNumber))  // logs false

some(callback[, thisObject]) повертає true , якщо callback повертає true для принаймні одного елемента в масиві.

function isNumber(value) {
  return typeof value === 'number'
}
let a1 = [1, 2, 3]
console.log(a1.some(isNumber))  // logs true
let a2 = [1, '2', 3]
console.log(a2.some(isNumber))  // logs true
let a3 = ['1', '2', '3']
console.log(a3.some(isNumber))  // logs false

reduce(callback[, initialValue])  застосовує callback(accumulator, currentValue[, currentIndex[, array]]) для кожного значення масиву з метою зменшення списку елементів до одного значення. Функція зменшення повертає кінцеве значення, повернене функцією callback .

Якщо вказано initialValue , тоді callback викликається initialValue як значення першого параметра, а значення першого елемента в масиві - як значення другого параметра.

Якщо initialValue не вказана, першими двома параметрами callback будуть перший і другий елементи масиву. При кожному наступному виклику значенням першого параметра буде будь-який callback , повернутий при попередньому виклику, а значення другого параметра буде наступним значенням масиву.

Якщо для callback  потрібен доступ до індексу оброблюваного елемента, для доступу до всього масиву вони доступні як необов'язкові параметри.

let a = [10, 20, 30]
let total = a.reduce(function(accumulator, currentValue) { return accumulator + currentValue }, 0)
console.log(total) // Prints 60

reduceRight(callback[, initialValue]) працює подібно  reduce(), але починається з останнього елемента.

reduce та reduceRight - найменш очевидний із ітеративних методів масиву. Їх слід використовувати для алгоритмів, що поєднують два значення рекурсивно, щоб зменшити послідовність до одного значення.

Багатовимірні масиви

Масиви можуть бути вкладені, тобто масив може містити інший масив як елемент. Використовуючи цю характеристику масивів JavaScript, можна створити багатовимірні масиви.

Наступний код створює багатовимірний масив.

let a = new Array(4)
for (let i = 0; i < 4; i++) {
  a[i] = new Array(4)
  for (let j = 0; j < 4; j++) {
    a[i][j] = '[' + i + ', ' + j + ']'
  }
}

Цей приклад створює масив із таких рядків:

Row 0: [0, 0] [0, 1] [0, 2] [0, 3]
Row 1: [1, 0] [1, 1] [1, 2] [1, 3]
Row 2: [2, 0] [2, 1] [2, 2] [2, 3]
Row 3: [3, 0] [3, 1] [3, 2] [3, 3]

Масиви та регулярні вирази

Коли масив є результатом збігу між регулярним виразом і рядком, масив повертає властивості та елементи, які надають інформацію про збіг. Масив - це повернене значення RegExp.exec(), String.match(), і String.split(). Інформацію про використання масивів з регулярними виразами див Regular Expressions.

Робота з масиво-подібними об'єктами

Деякі об`єкти JavaScript, такі як NodeList повертають  document.getElementsByTagName() або об'єкт arguments, доступний в тілі функції, який виглядає і поводиться як масиви на поверхні, але не ділиться всіма їх методами. Наприклад, об'єкт arguments забезпечує атрибут length але не реалізує метод forEach().

Методи прототипу масиву можна викликати для інших об’єктів, подібних до масиву. наприклад:

function printArguments() {
  Array.prototype.forEach.call(arguments, function(item) {
    console.log(item)
  })
}

Методи прототипу масиву також можна використовувати і для рядків, оскільки вони забезпечують послідовний доступ до своїх символів аналогічно масивам:

Array.prototype.forEach.call('a string', function(chr) {
  console.log(chr)
})

Типізовані масиви

JavaScript typed arrays є схожими на масив об'єктів і забезпечують механізм доступу до необроблених бінарних даних. Як ви вже знаєте, об'єкт Array динамічно росте і скорочується і може мати будь-яке значення JavaScript. Рушії JavaScript виконують оптимізацію, щоб ці масиви були швидкими. Однак, оскільки веб-застосунки стають все більш потужними, додаючи такі функції, як маніпулювання аудіо та відео, доступ до необроблених даних за допомогою WebSockets тощо, стало зрозуміло, що є випадки, коли корисним буде код JavaScript для швидкого та легкого маніпулювати необробленими бінарними даними в типізованих масивах.

Буфери та представлення: типізовані архітектури масивів

Щоб досягти максимальної гнучкості та ефективності, JavaScript типізовані масиви розділили реалізацію на буфери (buffers) та представлення(views). Буфер (реалізований об'єктом ArrayBuffer) - це об'єкт, що представляє фрагмент даних; він не має формату, про який можна говорити, і не пропонує механізму доступу до його вмісту. Для доступу до пам'яті, що міститься в буфері, вам потрібно скористатися представленням. Представлення забезпечує контекст - тобто тип даних, початкове зміщення та кількість елементів - який перетворює дані у фактично набраний масив.

Typed arrays in an ArrayBuffer

ArrayBuffer

ArrayBuffer - це тип даних, який використовується для репрезентації загального буфера даних бінарних даних фіксованої довжини. Ви не можете безпосередньо маніпулювати вмістом ArrayBuffer; натомість ви створюєте типізоване представлення масиву або DataView який представляє буфер у певному форматі, і використовують його для читання та запису вмісту буфера.

Типізоване представлення масиву

Типізовані представлення масивів мають самостійно описові назви та надають представлення для всіх звичайних числових типів, таких як  Int8, Uint32, Float64 і так далі. Існує один спеціальний вид типізованого представлення масиву Uint8ClampedArray. Він фіксує значення між 0 та 255.  Це корисно, наприклад, для обробки даних Canvas.

Type Value Range Size in bytes Description Web IDL type Equivalent C type
Int8Array -128 to 127 1 8-bit two's complement signed integer byte int8_t
Uint8Array 0 to 255 1 8-bit unsigned integer octet uint8_t
Uint8ClampedArray 0 to 255 1 8-bit unsigned integer (clamped) octet uint8_t
Int16Array -32768 to 32767 2 16-bit two's complement signed integer short int16_t
Uint16Array 0 to 65535 2 16-bit unsigned integer unsigned short uint16_t
Int32Array -2147483648 to 2147483647 4 32-bit two's complement signed integer long int32_t
Uint32Array 0 to 4294967295 4 32-bit unsigned integer unsigned long uint32_t
Float32Array 1.2×10-38 to 3.4×1038 4 32-bit IEEE floating point number (7 significant digits e.g., 1.1234567) unrestricted float float
Float64Array 5.0×10-324 to 1.8×10308 8 64-bit IEEE floating point number (16 significant digits e.g., 1.123...15) unrestricted double double
BigInt64Array -263 to 263-1 8 64-bit two's complement signed integer bigint int64_t (signed long long)
BigUint64Array 0 to 264-1 8 64-bit unsigned integer bigint uint64_t (unsigned long long)

For more information, see JavaScript typed arrays and the reference documentation for the different TypedArray objects.