Array.from()

Функция создаёт новый массив на основе итерируемого или массивоподобного объекта.

Время чтения: меньше 5 мин

Кратко

Скопировано

Функция Array.from() создаёт новый массив на основе переданного объекта. Объект должен быть либо массивоподобным (как строка или объект arguments), либо итерируемым (как Set или Map).

Как пишется

Скопировано

Функция Array.from() принимает три аргумента, последние два из которых не обязательны:

  • Объект, на основе которого создаётся массив.
  • Функция преобразования элемента перед его добавлением в массив. Работает как метод map().
  • Значение, которое будет использоваться как this в функции из второго параметра.

Возвращает новый массив, составленный из элементов переданного объекта.

Пример

Скопировано

Массив из строки

Скопировано
        
          
          const arr = Array.from('дока')console.log(arr)// ['д', 'о', 'к', 'а']
          const arr = Array.from('дока')
console.log(arr)
// ['д', 'о', 'к', 'а']

        
        
          
        
      

Массив из Set

Скопировано
        
          
          const uniqueNumbers = new Set()uniqueNumbers.add(1)uniqueNumbers.add(2)uniqueNumbers.add(3)const arr = Array.from(uniqueNumbers)// [1, 2, 3]
          const uniqueNumbers = new Set()
uniqueNumbers.add(1)
uniqueNumbers.add(2)
uniqueNumbers.add(3)

const arr = Array.from(uniqueNumbers)
// [1, 2, 3]

        
        
          
        
      

Массив из NodeList

Скопировано

Получить URL из всех ссылок на странице:

        
          
          const linkElements = document.getElementsByTagName('a')const arrLinks = Array.from(linkElements, function(a) { return a.href })
          const linkElements = document.getElementsByTagName('a')
const arrLinks = Array.from(linkElements, function(a) { return a.href })

        
        
          
        
      

Как понять

Скопировано

В JavaScript и браузерных API есть много объектов, которые очень похожи на массив, но не являются им. Объекты могут выглядеть как массив, но не иметь всех методов массива: forEach(), map(), filter() и так далее.

Такие объекты приходится превращать в массивы для удобства работы с ними или для интеграции с библиотеками. Array.from() создан, чтобы решить проблему конвертации таких объектов в новый массив.

Array.from() работает не со всеми объектами. Объект должен обладать одним из двух свойств, чтобы его получилось превратить в массив:

  • Элементы объекта проиндексированы и объект имеет свойство length. Такие объекты называют массивоподобными, потому что именно эти свойства присущи массиву. Этим свойством обладают объекты arguments, NodeList, HTMLCollection.
  • Объект итерируемый, то есть реализует интерфейс Iterable. Этим свойством обладают объекты Set и Map.

Array.from() перебирает каждый элемент и добавляет его в новый массив. Если передан второй аргумент, то перед добавлением происходит преобразование элемента.

При создании массива происходит поверхностное копирование (shallow copy) элементов. Если исходный объект содержит итерируемые элементы являющиеся объектами, то эти объекты будут скопированы по ссылке. Изменения будут видны в полученном массиве при их последующем изменении в исходном объекте, и наоборот.

Например:

        
          
          // Создадим объекты книгconst bookObj1 = {  name: 'Война и мир',  author: 'Л. Н. Толстой',  filmYears: [1913, 1915, 1956]}const bookObj2 = {  name: 'Братья Карамазовы',  author: 'Ф. М. Достоевский',  filmYears: [1915, 1920, 1931, 1969]}// Создадим Set и добавим в него книгиconst bookSet = new Set()bookSet.add(bookObj1)bookSet.add(bookObj2)// Создадим массив из Setconst bookArray = Array.from(bookSet)// Добавим экранизацию 'Войны и мира' в исходный объектbookObj1.filmYears.push(1965)// Изменение отразится и на массивеconsole.log(bookArray[0])// const bookObj1 = {//  name: 'Война и мир',//  author: 'Л. Н. Толстой',//  filmYears: [1913, 1915, 1956, 1965]// }
          // Создадим объекты книг
const bookObj1 = {
  name: 'Война и мир',
  author: 'Л. Н. Толстой',
  filmYears: [1913, 1915, 1956]
}
const bookObj2 = {
  name: 'Братья Карамазовы',
  author: 'Ф. М. Достоевский',
  filmYears: [1915, 1920, 1931, 1969]
}

// Создадим Set и добавим в него книги
const bookSet = new Set()
bookSet.add(bookObj1)
bookSet.add(bookObj2)

// Создадим массив из Set
const bookArray = Array.from(bookSet)

// Добавим экранизацию 'Войны и мира' в исходный объект
bookObj1.filmYears.push(1965)

// Изменение отразится и на массиве
console.log(bookArray[0])
// const bookObj1 = {
//  name: 'Война и мир',
//  author: 'Л. Н. Толстой',
//  filmYears: [1913, 1915, 1956, 1965]
// }

        
        
          
        
      

На практике

Скопировано

Николай Лопин советует

Скопировано

🛠 Если вызвать Array.from() без аргументов, то произойдёт ошибка «TypeError: undefined is not iterable (cannot read property Symbol(Symbol.iterator))».

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

Вместо последовательного вызова Array.from() и .map():

        
          
          const name = 'Mike'const spacedLetters = Array.from(name).map(function (letter) {    return `*${letter}*`})console.log(spacedLetters)// ['*M*', '*i*', '*k*', '*e*']
          const name = 'Mike'
const spacedLetters = Array.from(name).map(function (letter) {
    return `*${letter}*`
})

console.log(spacedLetters)
// ['*M*', '*i*', '*k*', '*e*']

        
        
          
        
      

...можно записать один вызов Array.from() со вторым аргументом:

        
          
          const name = 'Mike'const spacedLetters = Array.from(name, function(letter) { return `*${letter}*` })
          const name = 'Mike'
const spacedLetters = Array.from(name, function(letter) { return `*${letter}*` })

        
        
          
        
      

При выполнении этого кода не создаётся промежуточный массив.

🛠 Можно использовать Array.from(), чтобы генерировать последовательности значений без использования классического цикла for.

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

        
          
          const nums = Array.from({length: 4}, function(value, index) {  // value будет undefined  return index * 2})console.log(nums)// [0, 2, 4, 6]
          const nums = Array.from({length: 4}, function(value, index) {
  // value будет undefined
  return index * 2
})

console.log(nums)
// [0, 2, 4, 6]