TypedArrays y datos binarios en JavaScript | Nicolás Garzón
Los datos binarios son secuencias de bytes. JavaScript los representa mediante un buffer de memoria y una o más vistas que interpretan esos bytes.
JavaScript
Copiar const buffer = new ArrayBuffer ( 4 ) ;
const bytes = new Uint8Array ( buffer) ;
bytes[ 0 ] = 255 ;
bytes[ 1 ] = 10 ; Un array normal puede contener cualquier valor de JavaScript.
JavaScript
Copiar const values = [
1 ,
"two" ,
{ three : 3 } ,
] ; Un TypedArray representa una secuencia numérica con:
Tipo de elemento definido.
Tamaño por elemento conocido.
Memoria binaria contigua o administrada como un bloque.
Longitud fija para esa vista.
Archivos.
Imágenes, audio y video.
Protocolos de red.
Compresión.
Criptografía mediante APIs especializadas.
WebGL y gráficos.
WebAssembly.
Procesamiento numérico.
JavaScript
Copiar const buffer = new ArrayBuffer ( 8 ) ; Reserva un bloque de ocho bytes inicializados en cero.
JavaScript
Copiar buffer. byteLength; Un ArrayBuffer no ofrece acceso numérico directo.
JavaScript
Copiar buffer[ 0 ] ; JavaScript
Copiar const view = new Uint8Array ( buffer) ; Texto
Copiar ArrayBuffer
┌────┬────┬────┬────┐
│ 00 │ 00 │ 00 │ 00 │
└────┴────┴────┴────┘
↑
Uint8Array interpreta cada bytePuede haber varias vistas sobre el mismo buffer.
JavaScript
Copiar const buffer = new ArrayBuffer ( 4 ) ;
const bytes = new Uint8Array ( buffer) ;
const number = new Uint32Array ( buffer) ; Ambas observan la misma memoria, pero la agrupan de manera distinta.
JavaScript
Copiar bytes[ 0 ] = 1 ;
number[ 0 ] ; El resultado numérico depende también del orden de bytes utilizado por la plataforma para TypedArrays multibyte.
TypedArray describe una familia de constructores. No se utiliza directamente con new TypedArray().
Constructores habituales:
Int8Array.
Uint8Array.
Uint8ClampedArray.
Int16Array.
Uint16Array.
Int32Array.
Uint32Array.
Float16Array.
Float32Array.
Float64Array.
BigInt64Array.
BigUint64Array.
Cada uno define cómo interpreta sus elementos.
Uint8Array representa enteros sin signo de 8 bits:
Int8Array representa enteros con signo:
JavaScript
Copiar const values = new Uint8Array ( 2 ) ;
values[ 0 ] = 255 ;
values[ 1 ] = 256 ; El segundo valor se convierte al rango disponible.
JavaScript
Copiar values[ 1 ] ; No lanza automáticamente por cada valor fuera de rango; aplica las reglas de conversión del tipo.
Uint8ClampedArray limita valores al rango 0–255 en lugar de envolverlos como Uint8Array.
JavaScript
Copiar const values = new Uint8ClampedArray ( 3 ) ;
values[ 0 ] = - 20 ;
values[ 1 ] = 300 ;
values[ 2 ] = 10.8 ; Los resultados quedan dentro del rango y aplican las reglas de redondeo definidas para este tipo.
Es frecuente en datos de píxeles, donde un canal de color no debería envolver 300 hasta otro valor pequeño.
JavaScript
Copiar const values = new Uint16Array ( 4 ) ; Crea un buffer suficiente para cuatro elementos de dos bytes.
JavaScript
Copiar values. length;
values. byteLength; JavaScript
Copiar const values = new Uint8Array ( [
10 ,
20 ,
30 ,
] ) ; Los valores se convierten al tipo numérico elegido.
JavaScript
Copiar const buffer = new ArrayBuffer ( 16 ) ;
const values = new Uint32Array (
buffer,
4 ,
2 ,
) ; Texto
Copiar buffer, byteOffset, lengthEsta vista comienza en el byte 4 y contiene dos enteros de 32 bits.
El offset debe respetar la alineación requerida por el tipo.
JavaScript
Copiar new Uint32Array ( buffer, 1 ) ;
JavaScript
Copiar values. buffer;
values. byteOffset;
values. byteLength;
values. length;
values. BYTES_PER_ELEMENT ;
buffer: memoria subyacente.
byteOffset: byte donde comienza la vista.
byteLength: cantidad de bytes visibles.
length: cantidad de elementos.
BYTES_PER_ELEMENT: bytes por elemento.
JavaScript
Copiar const values = new Uint8Array ( [ 1 , 2 , 3 ] ) ;
Array. isArray ( values) ; Pero son iterables y ofrecen muchos métodos parecidos:
JavaScript
Copiar [ ... values] ;
values. map ( ( value ) => value * 2 ) ;
values. filter ( ( value ) => value > 1 ) ;
values. reduce ( ( sum, value ) => sum + value, 0 ) ; Los métodos que producen otro TypedArray convierten los resultados nuevamente al tipo de destino.
JavaScript
Copiar new Uint8Array ( [ 200 ] ) . map (
( value ) => value * 2 ,
) ;
No existen métodos como push, pop, shift, unshift o splice para cambiar su cantidad de elementos.
JavaScript
Copiar const values = new Uint8Array ( 3 ) ; Puedes modificar posiciones, pero no añadir una cuarta posición a la vista.
JavaScript
Copiar values[ 0 ] = 10 ;
values[ 3 ] = 40 ; La escritura fuera de rango no amplía el TypedArray.
Si necesitas otra longitud, crea otra vista o buffer.
Copia valores dentro de la vista existente.
JavaScript
Copiar const target = new Uint8Array ( 5 ) ;
target. set ( [ 10 , 20 ] , 1 ) ;
Si los datos no caben, lanza RangeError.
También puede copiar desde otro TypedArray, incluso cuando comparten buffer; la operación maneja el solapamiento según su contrato.
JavaScript
Copiar const values = new Uint8Array ( [
10 ,
20 ,
30 ,
40 ,
] ) ;
const section = values. subarray ( 1 , 3 ) ; section es otra vista sobre el mismo buffer.
JavaScript
Copiar section[ 0 ] = 99 ;
values[ 1 ] ; JavaScript
Copiar const copy = values. slice ( 1 , 3 ) ; Crea un TypedArray nuevo con un buffer distinto.
JavaScript
Copiar copy[ 0 ] = 5 ;
values[ 1 ] ; Texto
Copiar subarray → vista compartida
slice → copia de los elementosDataView permite leer y escribir distintos tipos dentro del mismo buffer y elegir explícitamente el endianness.
JavaScript
Copiar const buffer = new ArrayBuffer ( 8 ) ;
const view = new DataView ( buffer) ;
view. setUint16 ( 0 , 500 , true ) ;
const value = view. getUint16 ( 0 , true ) ; El tercer argumento true indica little-endian.
Sin él, los métodos multibyte utilizan big-endian por defecto.
DataView es útil para protocolos o formatos donde cada campo tiene un tipo y orden de bytes definido.
Un número de varios bytes puede almacenarse con el byte menos significativo primero o con el más significativo primero.
Ejemplo conceptual para 0x1234:
Texto
Copiar Big-endian: 12 34
Little-endian: 34 12TypedArrays utilizan el orden nativo de la plataforma. DataView permite especificarlo para leer formatos externos de manera portable.
No adivines el orden de un protocolo; sigue su especificación.
JavaScript
Copiar const values = new Float32Array ( [
0.1 ,
1.5 ,
] ) ; Los floats almacenan aproximaciones con una precisión limitada.
JavaScript
Copiar values[ 0 ] ; Puede no ser exactamente el mismo Number decimal escrito inicialmente.
Float16Array, estandarizado en ECMAScript 2025, utiliza menor precisión y memoria por elemento. Comprueba soporte cuando apuntes a runtimes anteriores.
JavaScript
Copiar const values = new BigInt64Array ( [
1n ,
2n ,
] ) ; Trabajan con BigInt, no con Number.
JavaScript
Copiar values[ 0 ] = 1 ;
values[ 0 ] = 1n ; No mezcles operaciones aritméticas entre Number y BigInt sin una conversión explícita y segura.
JavaScript
Copiar const buffer = new ArrayBuffer ( 4 ) ;
const bytes = new Uint8Array ( buffer) ;
const view = new DataView ( buffer) ;
view. setUint16 ( 0 , 0x1234 , false ) ;
bytes[ 0 ] ;
bytes[ 1 ] ; Modificar una vista se refleja en las demás porque la memoria es la misma.
Esto es útil, pero obliga a conocer quién puede escribir y qué interpretación usa cada vista.
Los runtimes modernos pueden admitir ArrayBuffer redimensionable.
JavaScript
Copiar const buffer = new ArrayBuffer ( 8 , {
maxByteLength : 64 ,
} ) ; JavaScript
Copiar buffer. resize ( 16 ) ; Algunas vistas pueden seguir la longitud del buffer y otras conservar una longitud fija según cómo fueron creadas.
Estas APIs necesitan compatibilidad reciente y un diseño cuidadoso: reducir un buffer puede dejar vistas fuera de límites temporal o permanentemente.
Un buffer puede transferirse entre contextos compatibles para mover su propiedad sin copiar todos los bytes.
Después de la transferencia, el buffer original puede quedar detached y dejar de ser utilizable.
Este mecanismo aparece en structured clone, workers y APIs de comunicación.
No se debe seguir usando una referencia después de transferir su almacenamiento.
JavaScript
Copiar const text = "ñ" ;
text. length; Un carácter puede ocupar varios bytes según la codificación.
En entornos web y runtimes modernos:
JavaScript
Copiar const encoder = new TextEncoder ( ) ;
const bytes = encoder. encode ( "Hola" ) ; JavaScript
Copiar const decoder = new TextDecoder ( ) ;
const text = decoder. decode ( bytes) ; TextEncoder y TextDecoder son APIs del entorno, no sintaxis central del lenguaje. Normalmente trabajan con UTF-8 y reglas definidas por la plataforma.
ECMAScript 2026 incorpora conversiones directas sobre Uint8Array.
JavaScript
Copiar const bytes = Uint8Array. fromHex ( "486f6c61" ) ;
bytes. toHex ( ) ; JavaScript
Copiar const bytes = Uint8Array. fromBase64 ( encoded) ;
bytes. toBase64 ( ) ; También existen métodos para escribir dentro de una vista existente.
JavaScript
Copiar bytes. setFromHex ( hexText) ;
bytes. setFromBase64 ( base64Text) ; Son APIs recientes. Comprueba soporte o utiliza utilidades del runtime cuando necesites compatibilidad con versiones anteriores.
JavaScript
Copiar JSON . stringify (
new Uint8Array ( [ 10 , 20 ] ) ,
) ; No produce automáticamente un formato binario portable estándar. Dependiendo de la serialización, puede aparecer como un objeto de propiedades numéricas.
Para transporte define explícitamente una representación:
Array de números.
Base64.
Hexadecimal.
Archivo binario.
Buffer enviado por una API que lo soporte.
La opción depende del tamaño y del protocolo.
JavaScript
Copiar const copy = new Uint8Array ( original) ; Copia sus valores a otro buffer.
JavaScript
Copiar const view = new Uint8Array (
original. buffer,
original. byteOffset,
original. length,
) ; Crea otra vista compartida.
Distingue siempre copiar valores de crear una vista .
Datos binarios externos pueden estar incompletos o mal formados.
Comprueba longitudes.
Valida offsets.
Sigue el formato esperado.
Limita tamaños.
Maneja errores de decodificación.
No confíes en campos de longitud sin compararlos con los bytes disponibles.
JavaScript
Copiar function readHeader ( buffer ) {
if ( buffer. byteLength < 4 ) {
throw new RangeError (
"Header requires four bytes" ,
) ;
}
const view = new DataView ( buffer) ;
return view. getUint32 ( 0 , false ) ;
} JavaScript
Copiar function createMessageHeader ( {
version,
type,
payloadLength,
} ) {
const buffer = new ArrayBuffer ( 6 ) ;
const view = new DataView ( buffer) ;
view. setUint8 ( 0 , version) ;
view. setUint8 ( 1 , type) ;
view. setUint32 (
2 ,
payloadLength,
false ,
) ;
return new Uint8Array ( buffer) ;
} La estructura queda definida byte por byte y puede enviarse mediante una API binaria compatible.
Confundir ArrayBuffer con un array de números.
Esperar acceso directo mediante buffer[0].
Pensar que un TypedArray es un Array normal.
Intentar cambiar su longitud con push.
Confundir subarray con una copia.
Ignorar que varias vistas pueden compartir memoria.
Asumir un endianness para datos externos.
Esperar que valores fuera de rango lancen siempre un error.
Mezclar Number y BigInt.
Creer que un carácter equivale siempre a un byte.
Usar APIs recientes de Base64 o hexadecimal sin revisar soporte.
Leer offsets sin comprobar la longitud disponible.
ArrayBuffer almacena bytes; una vista los interpreta.
TypedArrays tienen tipo numérico y longitud fija.
Varias vistas pueden compartir el mismo buffer.
subarray comparte memoria; slice copia.
DataView permite mezclar tipos y controlar endianness.
TypedArrays son iterables, pero Array.isArray devuelve false.
Los valores se convierten al rango y precisión del tipo.
Texto y bytes necesitan una codificación.
Las APIs binarias recientes requieren comprobar compatibilidad.
Los datos externos deben validarse antes de leerse.
¿Por qué cambiar section[0] también modifica values[1]?
JavaScript
Copiar const values = new Uint8Array ( [
10 ,
20 ,
30 ,
] ) ;
const section = values. subarray ( 1 ) ;
section[ 0 ] = 99 ; Respuesta Porque subarray crea otra vista sobre el mismo ArrayBuffer; no copia los bytes. section[0] y values[1] representan la misma ubicación de memoria.
El siguiente bloque estudia errores y confiabilidad : tipos de error, throw, try...catch, errores personalizados, validación, depuración y modo estricto.