JavaScript ArrayBuffer y Arrays Binarios
JavaScript ofrece ArrayBuffer y arrays tipados para manejar datos binarios en archivos, imágenes, audio, WebSockets y respuestas fetch de forma eficiente.
La mayor parte del tiempo JavaScript trabaja con texto y JSON, pero en el momento en que tocas archivos, imágenes, audio, WebSockets o respuestas fetch, estás lidiando con bytes crudos. JavaScript gestiona esos bytes mediante ArrayBuffer y una familia de vistas de array tipado. Este capítulo explica qué es cada pieza, cómo se relacionan y cuándo usarlas, con ejemplos ejecutables que puedes verificar tú mismo.
El modelo mental tiene dos capas:
ArrayBuffer— un bloque de memoria cruda de longitud fija. Son solo bytes; no puedes leerlos ni escribirlos directamente.- Vistas (arrays tipados y
DataView) — objetos que interpretan esos bytes como números. Siempre lees y escribes a través de una vista.
¿Qué es un ArrayBuffer?
Un ArrayBuffer es un contenedor genérico de longitud fija para datos binarios crudos: un bloque de memoria medido en bytes. No tiene noción de "elementos" ni de tipos; solo sabe cuántos bytes contiene. Su tamaño se establece en el momento de la creación y no puede cambiar.
Para hacer algo con esos bytes, debes envolver el buffer en una vista.
Arrays tipados: vistas sobre un buffer
Un array tipado es una vista que interpreta el buffer como un array de números de un tipo fijo. La indexación, la iteración y la aritmética funcionan igual que con un array normal, pero los datos residen en la memoria cruda del buffer, lo que hace que los arrays tipados sean compactos y rápidos para grandes conjuntos de datos numéricos.
El tipo de vista determina cuántos bytes ocupa cada elemento:
| Vista | Bytes por elemento | Rango de valores |
|---|---|---|
Uint8Array | 1 | 0 … 255 |
Int8Array | 1 | -128 … 127 |
Uint16Array | 2 | 0 … 65535 |
Int16Array | 2 | -32768 … 32767 |
Uint32Array | 4 | 0 … 4294967295 |
Int32Array | 4 | -2³¹ … 2³¹-1 |
Float32Array | 4 | float de 32 bits |
Float64Array | 8 | float de 64 bits |
Uint8ClampedArray | 1 | 0 … 255 (con saturación) |
Crear arrays tipados
Puedes construir un array tipado a partir de una longitud, de un array existente o sobre un buffer existente.
Varias vistas pueden compartir un mismo buffer
Esta es la idea clave: múltiples vistas pueden situarse sobre el mismo buffer. Escribir a través de una vista cambia los bytes, y todas las demás vistas ven el cambio de inmediato. Así es como se reinterpretan los mismos bytes de diferentes maneras.
Desbordamiento y saturación
Cada elemento tiene un ancho fijo, por lo que los valores fuera de rango se envuelven (se toman en módulo del tamaño del tipo). Uint8ClampedArray es la excepción: en lugar de eso, satura al rango 0…255, que es exactamente lo que necesitan los datos de píxeles de canvas.
Segmentación y sub-vistas
slice() copia en un nuevo buffer independiente, mientras que subarray() devuelve otra vista sobre la misma memoria — más económico, pero las escrituras son compartidas.
DataView: tipos mixtos y orden de bytes
Un array tipado impone un solo tipo y usa el orden de bytes nativo de la plataforma. DataView es la alternativa de bajo nivel: permite leer y escribir diferentes tipos en cualquier desplazamiento de byte, y te permite elegir el orden de bytes (endianness) de forma explícita. Ese control es esencial cuando se analizan formatos de archivo y protocolos de red, donde el orden de bytes está fijado por una especificación y no por tu CPU.
Endianness es el orden en que se almacena un número de múltiples bytes: big-endian pone el byte más significativo primero, little-endian lo pone al final. Cada método get/set de DataView acepta un indicador littleEndian (por defecto es big-endian).
Aquí se muestra el mismo número de 32 bits escrito en ambos órdenes de bytes para que puedas ver la diferencia:
Conversión entre bytes y otros tipos
Los datos binarios rara vez existen solos: constantemente se mueven entre buffers, strings y objetos de nivel superior.
Bytes ↔ texto
Para convertir un string en bytes (y viceversa), usa TextEncoder / TextDecoder, que codifican en UTF-8. Consulta TextDecoder y TextEncoder para ver la API completa.
Acceder al buffer subyacente
Cada array tipado expone su buffer, junto con byteOffset y byteLength, que describen la región que cubre. Así es como pasas bytes a una API que espera un ArrayBuffer.
Dónde se usan realmente los arrays binarios
- Archivos. Leer un archivo como
ArrayBufferpermite inspeccionar cabeceras, analizar formatos o subir bytes crudos. Consulta Blob y la API de File. - Red.
fetch(...).arrayBuffer()y los frames binarios de WebSocket te dan unArrayBufferpara decodificar. - Canvas.
ctx.getImageData().dataes unUint8ClampedArrayde bytes de píxeles RGBA que puedes leer y reescribir. - WebGL / Web Audio. Los buffers de vértices y las muestras de audio son arrays tipados por rendimiento.
Ejemplo: leer un archivo como ArrayBuffer
En el navegador, FileReader (o el más moderno Blob.arrayBuffer()) lee el contenido de un archivo en un buffer que luego analizas con un DataView o un array tipado. Para una guía más completa, consulta la API de File.
function readBinaryFile(file) {
const reader = new FileReader();
reader.onload = () => {
const view = new DataView(reader.result);
console.log(view.getUint8(0)); // first byte, e.g. a format signature
};
reader.readAsArrayBuffer(file);
}
// Modern alternative:
// const buffer = await file.arrayBuffer();Buenas prácticas
- Elige el tipo más pequeño que sea suficiente.
Uint8Arraypara flujos de bytes,Float64Arraypara matemáticas precisas — usar un tipo más amplio del necesario desperdicia memoria. - Usa
DataViewsolo cuando necesites tipos mixtos o un endianness fijo. Para un array numérico uniforme, un array tipado es más sencillo y rápido. - Reutiliza buffers en bucles críticos para reducir la asignación de memoria y la carga del recolector de basura.
- Recuerda que las vistas comparten memoria — usa
slice()cuando necesites una copia independiente,subarray()cuando intencionalmente quieras crear un alias.
Resumen
- Un
ArrayBufferes memoria cruda de longitud fija; nunca lo tocas directamente. - Los arrays tipados ven esa memoria como números de un tipo fijo y se comportan como arrays.
DataViewlee y escribe tipos mixtos en desplazamientos arbitrarios con endianness explícito — ideal para analizar protocolos y formatos de archivo.- Las vistas sobre el mismo buffer comparten memoria, por lo que una escritura a través de una es visible a través de todas.
- Estos tipos potencian archivos, respuestas de red, píxeles de canvas, audio y WebGL.