Кратко
СкопированоData помогает работать с содержимым Array. С его помощью можно читать и записывать данные разных типов, а также указывать порядок байтов.
Пример
Скопировано
const buffer = new ArrayBuffer(4)const dataView = new DataView(buffer)dataView.setUint8(0, 255)dataView.setUint8(1, 255)console.log(dataView.getUint8(0))// 255console.log(dataView.getUint16(0))// 65535
const buffer = new ArrayBuffer(4)
const dataView = new DataView(buffer)
dataView.setUint8(0, 255)
dataView.setUint8(1, 255)
console.log(dataView.getUint8(0))
// 255
console.log(dataView.getUint16(0))
// 65535
Как пишется
СкопированоСоздать Data можно с помощью оператора new:
new DataView(buffer, [byteOffset], [byteLength])
new DataView(buffer, [byteOffset], [byteLength])
Data при создании принимает следующие аргументы:
buffer— объектArray;Buffer byte— смещение по даннымOffset Array(в байтах), с учетом которого будет создаваться представлениеBuffer Data. По умолчанию — 0;View byte— количество байтов, доступных в создаваемом представлении. По умолчанию — все данные до конца буфера.Length
Создание представления
СкопированоМожно создать Data для всего буфера:
// Создаём буфер размером 16 байтconst buffer = new ArrayBuffer(16)// Создаём представление для всего буфераconst dataView = new DataView(buffer)
// Создаём буфер размером 16 байт
const buffer = new ArrayBuffer(16)
// Создаём представление для всего буфера
const dataView = new DataView(buffer)
Или для части буфера, указав смещение и длину:
const buffer = new ArrayBuffer(16)// Создаём представление, которое начинается// со смещением на 2 байта от начала buffer и занимает 4 байтаconst dataView = new DataView(buffer, 2, 4)
const buffer = new ArrayBuffer(16)
// Создаём представление, которое начинается
// со смещением на 2 байта от начала buffer и занимает 4 байта
const dataView = new DataView(buffer, 2, 4)
Свойства
СкопированоУ Data есть три основных свойства:
buffer— ссылка на исходныйArray;Buffer byte— смещение представления от начала буфера в байтах;Offset byte— размер представления в байтах.Length
Методы
СкопированоМетоды Data начинаются с get (чтение) или set (запись), а дальше указывается тип данных: Uint8, Int16, Float32 и так далее. Например:
// Создаем бинарный массив размером 4 байтаconst buffer = new Uint8Array([0, 42, 0, 42]).bufferconst dataView = new DataView(buffer)// Читаем 8-битное число с позиции 0console.log(dataView.getUint8(0))// 0// Читаем 16-битное число с позиции 0 (оно состоит из двух байт)console.log(dataView.getUint16(0))// 42// Читаем 32-битное число с позиции 0 (оно состоит из четырех байт)console.log(dataView.getUint32(0))// 2752554// Записываем 0 на позицию 0 для 16-битного числаdataView.setUint16(0, 0)// Теперь 32-битное число изменилосьconsole.log(dataView.getUint32(0))// 42
// Создаем бинарный массив размером 4 байта
const buffer = new Uint8Array([0, 42, 0, 42]).buffer
const dataView = new DataView(buffer)
// Читаем 8-битное число с позиции 0
console.log(dataView.getUint8(0))
// 0
// Читаем 16-битное число с позиции 0 (оно состоит из двух байт)
console.log(dataView.getUint16(0))
// 42
// Читаем 32-битное число с позиции 0 (оно состоит из четырех байт)
console.log(dataView.getUint32(0))
// 2752554
// Записываем 0 на позицию 0 для 16-битного числа
dataView.setUint16(0, 0)
// Теперь 32-битное число изменилось
console.log(dataView.getUint32(0))
// 42
Посмотреть список всех методов Data можно в спецификации.
Указание порядка байтов
СкопированоПорядок байтов (endianness) — это последовательность байтов которая используется для хранения чисел в памяти. По умолчанию Data использует порядок от старшего к младшему (big-endian). Подробнее о памяти можно узнать из статьи «Как устроена память».
Data позволяет явно указать порядок байтов т. к. принимает флаг little-endian при чтении или записи. В обычных типизированных массивах такой возможности нет. Это особенно важно, когда порядок байтов в данных отличается от порядка, используемого в операционной системе.
const buffer = new ArrayBuffer(4)const dataView = new DataView(buffer)// Записываем число 123 с указанием порядка big-endian (false)dataView.setUint16(0, 123, false)// Читаем число с указанием порядка big-endianconsole.log(dataView.getUint16(0, false))// 123 - все верно// Читаем число, как будто оно записано в порядке little-endianconsole.log(dataView.getUint16(0, true))// 31488 - получили другое число!
const buffer = new ArrayBuffer(4)
const dataView = new DataView(buffer)
// Записываем число 123 с указанием порядка big-endian (false)
dataView.setUint16(0, 123, false)
// Читаем число с указанием порядка big-endian
console.log(dataView.getUint16(0, false))
// 123 - все верно
// Читаем число, как будто оно записано в порядке little-endian
console.log(dataView.getUint16(0, true))
// 31488 - получили другое число!
Порядок байтов в используемом окружении
Вот пример, как с помощью Data можно узнать порядок байтов в используемом окружении:
const littleEndian = (() => { const buffer = new ArrayBuffer(2) // Указываем, что данные записываются в формате little-endian (true) new DataView(buffer).setInt16(0, 256, true) // Типизированные массивы используют порядок байтов платформы return new Int16Array(buffer)[0] === 256})()// Вернет true для little-endian или false для big-endianconsole.log(littleEndian)
const littleEndian = (() => {
const buffer = new ArrayBuffer(2)
// Указываем, что данные записываются в формате little-endian (true)
new DataView(buffer).setInt16(0, 256, true)
// Типизированные массивы используют порядок байтов платформы
return new Int16Array(buffer)[0] === 256
})()
// Вернет true для little-endian или false для big-endian
console.log(littleEndian)
По умолчанию Data использует big-endian, но многие платформы работают и с little-endian.
Например, little-endian используется в x86 процессорах (Intel, AMD). Архитектура ARM тоже чаще использует little-endian.
При этом популярные сетевые протоколы (TCP/IP, UDP) и форматы файлов (JPEG, PNG) используют big-endian. Поэтому важно контролировать порядок байтов.
Как понять
СкопированоData — это низкоуровневый инструмент. Он пригодится, когда нужно работать с бинарными данными: изображениями, аудио, видео или сетевыми запросами.
Его особенность — возможность указать порядок байтов при чтении и записи. Это позволяет работать с данными, у которых порядок байтов отличается от порядка байтов в системе. А ещё Data полезен, если в буфере хранятся данные разного типа (например, сами данные и служебная информация к ним).
Выход за границы буфера
СкопированоData сам следит за тем, чтобы вы не вышли за границы буфера. Если попытаться прочитать данные за пределами Array, возникнет ошибка Range.
const buffer = new ArrayBuffer(2)const dataView = new DataView(buffer)console.log(dataView.getUint32(0))// Ошибка: Uncaught RangeError: Offset is outside the bounds of the DataViewconsole.log(dataView.getUint16(1))// Ошибка: Uncaught RangeError: Offset is outside the bounds of the DataView
const buffer = new ArrayBuffer(2)
const dataView = new DataView(buffer)
console.log(dataView.getUint32(0))
// Ошибка: Uncaught RangeError: Offset is outside the bounds of the DataView
console.log(dataView.getUint16(1))
// Ошибка: Uncaught RangeError: Offset is outside the bounds of the DataView
На практике
Скопированосоветует
СкопированоData даёт гибкость и контроль, но это достигается ценой производительности. При каждом чтении или записи Data выполняет дополнительные проверки, (согласно спецификации ECMAScript) — например, проверяет границы буфера и порядок байтов.
Для большинства задач разница в скорости незаметна. Но в высокопроизводительных сценариях (например, обработка каждого пикселя изображения) использование типизированных массивов через uint8array или uint8array сработает значительно быстрее, чем методы Data.