19.1 Del concepto al dato
La matemática define qué es un vector y cómo se opera. El programa necesita además decidir cómo almacenarlo. En JavaScript podemos usar objetos, arreglos, arreglos tipados o instancias de una clase.
Ninguna representación es universalmente superior. La decisión depende de la claridad requerida, la cantidad de datos, las bibliotecas utilizadas y el costo de las operaciones.
19.2 Objetos con propiedades nombradas
La forma más legible para comenzar es un objeto:
const desplazamiento = { x: 3, y: -2 };
const modulo = Math.hypot(desplazamiento.x, desplazamiento.y);
console.log(desplazamiento, modulo);x e y expresan la intención y reducen errores de índice. Podemos agregar metadatos, aunque conviene no mezclar indiscriminadamente valores matemáticos y estado de la aplicación.
19.3 Fábricas y valores iniciales
Una función fábrica centraliza la creación y evita compartir accidentalmente el mismo objeto:
const vector2 = (x = 0, y = 0) => ({ x, y });
const posicion = vector2(4, 1);
const velocidad = vector2();
console.log(posicion, velocidad, posicion !== velocidad);No debe reutilizarse un único objeto cero para estados que luego serán mutados.
19.4 Funciones puras e inmutabilidad
Una función pura devuelve un objeto nuevo y no altera los argumentos:
function sumar(a, b) {
return { x: a.x + b.x, y: a.y + b.y };
}
function escalar(v, k) {
return { x: v.x * k, y: v.y * k };
}
const a = { x: 2, y: 1 }, b = { x: -1, y: 4 };
console.log(sumar(a, b), escalar(a, 3), a);Este enfoque facilita pruebas y razonamiento. Su costo es crear objetos nuevos, algo normalmente aceptable hasta medir que constituya un problema real.
19.5 Mutación controlada
En bucles intensivos puede actualizarse un objeto de salida para reducir asignaciones:
function sumarEn(out, a, b) {
out.x = a.x + b.x;
out.y = a.y + b.y;
return out;
}
const resultado = { x: 0, y: 0 };
console.log(sumarEn(resultado, {x:2,y:3}, {x:4,y:-1}));El nombre y la documentación deben advertir la mutación. No conviene optimizar de esta manera sin un perfil de rendimiento.
19.6 Arreglos numéricos
Un vector puede almacenarse como [x, y] o [x, y, z]. Esta forma facilita algoritmos genéricos, iteraciones y compatibilidad con APIs.
function sumarArreglos(a, b) {
if (a.length !== b.length) throw new Error("Dimensiones diferentes");
return a.map((valor, i) => valor + b[i]);
}
console.log(sumarArreglos([1, 2, 3], [4, -1, 2]));Los índices son menos expresivos: debemos acordar que 0 es x, 1 es y y 2 es z.
19.7 Arreglos tipados
Float32Array y Float64Array almacenan números en memoria contigua con precisión definida. Son habituales al transferir datos a WebGL, audio, procesamiento numérico o grandes colecciones.
const vector = new Float32Array([1.25, -3.5, 2]);
vector[0] *= 2;
console.log(Array.from(vector), vector.byteLength);Float32Array redondea a precisión simple. No posee todos los métodos mutables de un arreglo normal y su tamaño queda fijo.
19.8 Comparación de representaciones
| Representación | Ventaja | Compromiso |
|---|---|---|
| {x, y} | Legible y flexible | Más objetos y propiedades |
| [x, y] | Compacta y genérica | Índices menos claros |
| Float32Array | Interoperabilidad y memoria predecible | Precisión simple y tamaño fijo |
| Clase Vector2 | API agrupada y validable | Semántica de mutación debe quedar clara |
19.9 Una clase Vector2
Una clase reúne datos y operaciones. Aquí usamos métodos que devuelven instancias nuevas:
class Vector2 {
constructor(x = 0, y = 0) { this.x = x; this.y = y; }
sumar(v) { return new Vector2(this.x + v.x, this.y + v.y); }
escalar(k) { return new Vector2(this.x * k, this.y * k); }
modulo() { return Math.hypot(this.x, this.y); }
normalizado() {
const m = this.modulo();
return m === 0 ? null : this.escalar(1 / m);
}
}
const v = new Vector2(3, 4);
console.log(v.modulo(), v.normalizado());19.10 Métodos estáticos y de instancia
Un método de instancia como v.modulo() opera sobre un vector. Un método estático como Vector2.distancia(a, b) combina valores sin pertenecer naturalmente a uno solo.
Una API consistente debe decidir si sumar muta, devuelve un valor nuevo o escribe en un parámetro de salida. Mezclar estilos sin nombres claros genera errores difíciles de detectar.
19.11 Validación
JavaScript permite construir objetos con valores faltantes, textos, infinitos o NaN. Una frontera de entrada debe validar:
function esVector2(v) {
return v !== null
&& Number.isFinite(v.x)
&& Number.isFinite(v.y);
}
console.log(esVector2({x:3,y:4}), esVector2({x:"3",y:4}));No es necesario validar en cada operación interna si la arquitectura garantiza valores correctos desde su entrada.
19.12 Unidades y referencias
Un objeto puede incluir unidad y referencia, pero las operaciones deben comprobar compatibilidad. Otra estrategia es encapsular esos metadatos en el estado físico que contiene los vectores.
posicionM: { x: 2, y: 3 },
velocidadMps: { x: 1, y: 0 },
referencia: "mundo"
};
Los nombres con unidades reducen ambigüedad y evitan sumar, por ejemplo, metros con píxeles.
19.13 Conversión entre formatos
const objetoAArray = v => [v.x, v.y, ...(v.z === undefined ? [] : [v.z])];
const arrayAObjeto2 = a => ({ x: a[0], y: a[1] });
const objeto = { x: 2, y: -5 };
const arreglo = objetoAArray(objeto);
console.log(arreglo, arrayAObjeto2(arreglo));Conviene convertir en los límites de la aplicación y mantener una representación interna principal.
19.14 Copias, referencias y JSON
Los objetos y arreglos se asignan por referencia. const b = a no copia el vector; ambos nombres apuntan al mismo objeto. Para un objeto plano usamos {...a} y para un arreglo [...a].
Los objetos y arreglos normales se serializan con JSON. Un Float32Array requiere convertirlo, por ejemplo con Array.from, si queremos un arreglo JSON convencional. NaN e infinitos no se conservan correctamente como números JSON.
19.15 Laboratorio de representaciones
Modificá el vector y elegí una precisión tipada. El laboratorio muestra simultáneamente objeto, arreglo, arreglo tipado y JSON.
Todas las estructuras representan el mismo vector.
19.16 Rendimiento con criterio
La legibilidad suele ser prioritaria. Si una medición demuestra que las asignaciones o el diseño de memoria son un cuello de botella, podemos usar parámetros de salida, almacenamiento plano o arreglos tipados.
El rendimiento depende del motor, el volumen de datos y el patrón de acceso. Una microprueba aislada no reemplaza medir la aplicación real.
19.17 Errores frecuentes
- Asignar un objeto creyendo que se creó una copia.
- Mezclar métodos mutables e inmutables sin indicarlo.
- Confundir índices de un arreglo.
- Usar arreglos de distinta dimensión en la misma operación.
- Perder precisión al convertir a
Float32Arraysin evaluarlo. - Omitir unidades y referencias.
- Optimizar estructuras antes de medir.
- Confiar en JSON para conservar
NaNo infinitos.
19.18 Ejercicio integrador
Implementá una clase inmutable Vector3 con suma, escalado, producto escalar, módulo y normalización. Debe rechazar componentes no finitas y tratar el vector nulo.
Ver solución y código
class Vector3 {
constructor(x=0,y=0,z=0) {
if (![x,y,z].every(Number.isFinite)) throw new TypeError("Componentes inválidas");
this.x=x; this.y=y; this.z=z;
Object.freeze(this);
}
sumar(v) { return new Vector3(this.x+v.x,this.y+v.y,this.z+v.z); }
escalar(k) { return new Vector3(this.x*k,this.y*k,this.z*k); }
punto(v) { return this.x*v.x+this.y*v.y+this.z*v.z; }
modulo() { return Math.hypot(this.x,this.y,this.z); }
normalizado() { const m=this.modulo(); return m===0?null:this.escalar(1/m); }
}
const a=new Vector3(2,-1,2), b=new Vector3(1,3,0);
console.log(a.sumar(b),a.punto(b),a.modulo(),a.normalizado());19.19 Ideas para recordar
- Los objetos priorizan legibilidad; los arreglos facilitan algoritmos genéricos.
- Los arreglos tipados ofrecen memoria y precisión explícitas.
- Una clase puede reunir invariantes y operaciones.
- La API debe declarar claramente si muta o crea valores.
- Objetos y arreglos se asignan por referencia.
- Unidades, dimensiones y sistemas de referencia forman parte del diseño.
- Las optimizaciones deben responder a mediciones.
En el próximo tema construiremos una biblioteca reutilizable de operaciones vectoriales.