WhatsApp

  

Tipos de datos en JavaScript: Conceptos, ejemplos y buenas prácticas

Guía completa sobre los tipos de datos en JavaScript, con ejemplos, comparativas, trucos de tipado, rendimiento y seguridad.

Tipos de datos en JavaScript

JavaScript es un lenguaje dinámico y flexible, pero entender sus tipos de datos es esencial para escribir código fiable, mantenible y con buen rendimiento. En este artículo encontrarás una descripción exhaustiva de cada tipo, ejemplos prácticos, comparativas con otros lenguajes y recomendaciones de seguridad y optimización.

1. ¿Por qué importa el tipo de dato?

El motor JavaScript (V8, SpiderMonkey, JavaScriptCore, etc.) interpreta el código en tiempo de ejecución. Conocer los tipos permite:

  • Prevenir errores de runtime y bugs sutiles.
  • Optimizar el uso de memoria y el rendimiento del JIT.
  • Aplicar correctamente técnicas de sanitización y evitar vulnerabilidades como injection o prototype pollution.

2. Clasificación de los tipos

Tipos primitivos

Son inmutables y se copian por valor. JavaScript define seis primitivos:

  1. Number – incluye NaN y Infinity.
  2. BigInt – enteros de precisión arbitraria.
  3. String – secuencias de caracteres Unicode.
  4. Booleantrue o false.
  5. Symbol – identificadores únicos.
  6. undefined – valor por defecto de variables no inicializadas.
  7. null – referencia nula (intencional).

Ejemplos rápidos

let age = 27;                // Number
let big = 12345678901234567890n; // BigInt
let name = "Ana";            // String
let isReady = true;          // Boolean
let id = Symbol('uid');      // Symbol
let notSet;                  // undefined
let empty = null;            // null

Tipos de referencia (objetos)

Se almacenan en el heap y se copian por referencia. Incluyen:

  • Object – el tipo base para estructuras de datos.
  • Array – lista ordenada de valores.
  • Function – objetos invocables.
  • Date, RegExp, Map, Set, WeakMap, WeakSet – estructuras especializadas.
  • TypedArray – vistas de buffers binarios.

Ejemplo de creación y mutabilidad

let user = { name: "Luis", age: 30 };
user.age = 31;               // Mutación en el mismo objeto
let numbers = [1, 2, 3];
numbers.push(4);            // Modifica la referencia
function greet() { console.log('Hello'); }
// greet es un objeto Function y, como tal, tiene propiedades

Nota de seguridad: nunca confíes en datos externos para crear o modificar prototipos (Object.prototype), pues podrías abrir la puerta a prototype pollution.

3. Coerción de tipos y operadores de comparación

JavaScript efectúa coerción implícita en muchos contextos. Conocer cuándo ocurre evita sorpresas:

  • == vs ===: la primera convierte los operandos, la segunda no.
  • Operadores aritméticos convierten a Number (excepto + que concatena strings).

Ejemplos ilustrativos

0 == false          // true (coerción a Number)
0 === false         // false (tipo diferente)
"5" + 1            // "51" (concatenación)
"5" - 1            // 4 (coerción a Number)
null == undefined   // true
null === undefined  // false

Para código robusto, prefiere siempre === y !==. Cuando necesites conversión explícita, usa Number(), String(), Boolean() o BigInt().

4. Detectar tipos en tiempo de ejecución

typeof

Devuelve una cadena que describe el tipo primitivo o "object"/"function" para referencias.

typeof 42            // "number"
typeof "hi"         // "string"
typeof true          // "boolean"
typeof Symbol()      // "symbol"
typeof undefined     // "undefined"
typeof null          // "object" (quirk histórico)
typeof []            // "object"
typeof {}            // "object"
typeof (()=>{})      // "function"

instanceof

Comprueba la cadena de prototipos. Es útil para objetos y arrays.

[] instanceof Array          // true
{} instanceof Object          // true
new Date() instanceof Date    // true
function Foo() {}
new Foo() instanceof Foo      // true

Para valores primitivos instanceof siempre devuelve false. En entornos con múltiples contextos (iframes, workers) instanceof puede fallar; en esos casos Object.prototype.toString.call(value) es más fiable.

5. Mejores prácticas al trabajar con tipos

  • Usa const siempre que sea posible. Evita reasignaciones inesperadas.
  • Valida entradas externas. Emplea typeof y Array.isArray() antes de operar.
  • Prefiere estructuras inmutables. Usa Object.freeze() o librerías como Immer para evitar mutaciones accidentales.
  • Tipado estático opcional. Integra TypeScript o Flow para detectar errores de tipo en tiempo de compilación.
  • Evita la comparación con null y undefined usando el operador de coalescencia nula (??).

Ejemplo de validación robusta

function processUser(input) {
  if (typeof input !== "object" || input === null) {
    throw new TypeError("Se esperaba un objeto de usuario");
  }
  const { name, age } = input;
  if (typeof name !== "string" || name.trim() === "") {
    throw new TypeError("'name' debe ser una cadena no vacía");
  }
  if (!Number.isInteger(age) || age < 0) {
    throw new RangeError("'age' debe ser un entero positivo");
  }
  // lógica del negocio
}

6. Impacto de los tipos en rendimiento

Los motores modernos optimizan los hidden classes y la monomorfización de funciones. Mantener la consistencia de tipos ayuda al JIT a generar código más rápido.

  • Evita mezclar tipos en arrays (ej. [1, "a", true]) si el rendimiento es crítico.
  • Prefiere Number.isFinite() y Number.isNaN() sobre isNaN() para evitar conversiones implícitas.
  • Cuando trabajes con datos binarios, usa ArrayBuffer y TypedArray (Uint8Array, Float64Array, etc.) para evitar sobrecarga de objetos.

Benchmark rápido (Node.js)

const { performance } = require('perf_hooks');
function sumNumbers(arr) {
  let total = 0;
  for (let i = 0; i < arr.length; i++) total += arr[i];
  return total;
}
function sumMixed(arr) {
  let total = 0;
  for (let i = 0; i < arr.length; i++) total += +arr[i]; // coerción
  return total;
}
const size = 1e6;
const nums = Array.from({length:size}, (_,i)=>i);
const mixed = nums.map(v=> (v%2===0? v : `${v}`));
let t0 = performance.now();
sumNumbers(nums);
let t1 = performance.now();
sumMixed(mixed);
let t2 = performance.now();
console.log('Solo números:', (t1-t0).toFixed(2), 'ms');
console.log('Mezcla + coerción:', (t2-t1).toFixed(2), 'ms');

En la mayoría de los navegadores, la versión “solo números” será significativamente más rápida.

7. Seguridad relacionada con tipos

  • Validación de tipos antes de usar datos en eval, Function o plantillas de cadena. Un string inesperado puede ejecutar código arbitrario.
  • Evita el uso de Object.prototype.__proto__ o Object.setPrototypeOf en datos procedentes del cliente. Puede resultar en prototype pollution.
  • Sanitiza los valores que se convierten a Number antes de usarlos en consultas a bases de datos. NaN o Infinity pueden romper lógicas de paginación.

Ejemplo de mitigación de prototype pollution

function safeMerge(target, source) {
  const prohibited = ["__proto__", "prototype", "constructor"];
  for (const key of Object.keys(source)) {
    if (prohibited.includes(key)) continue; // descarta keys peligrosas
    target[key] = source[key];
  }
  return target;
}

8. Compatibilidad entre navegadores y Node.js

Los tipos básicos son universales, pero algunos como BigInt y globalThis solo están disponibles a partir de:

  • Chrome 67+, Firefox 68+, Safari 14+, Edge 79+ (Chromium).
  • Node.js 10.4+ (experimental) y 12+ (estable).

Para proyectos que deben soportar navegadores antiguos, utiliza Babel con el preset @babel/preset-env y polyfills de core-js.

9. Tabla comparativa de tipos (Resumen)

Tipo Categoría Mutabilidad Operaciones comunes Ejemplo
NumberPrimitivoInmutable+, -, *, /, %42
BigIntPrimitivoInmutable+, -, *, / (sin decimales)123n
StringPrimitivoInmutableconcatenación, slice, replace"hola"
BooleanPrimitivoInmutable&&, ||, !true
SymbolPrimitivoInmutabledescripción, uso como clavesSymbol('id')
undefinedPrimitivoInmutablecomparaciones, typeoflet x;
nullPrimitivoInmutablecomparaciones, asignaciónlet y = null;
ObjectReferenciaMutablepropiedad, spread, Object.assign{a:1}
ArrayReferenciaMutablepush, map, filter, reduce[1,2,3]
FunctionReferenciaMutable (propiedades)call, apply, bindfunction(){}

10. Conclusión

Dominar los tipos de datos en JavaScript es la base para escribir código seguro, rápido y fácil de mantener. Aplica las buenas prácticas aquí descritas, considera integrar TypeScript para un tipado estático y mantente al día con las mejoras de los motores JavaScript.



Tipos de datos en JavaScript: Conceptos, ejemplos y buenas prácticas
ASIMOV Ingeniería S. de R.L. de C.V., Emiliano Nava 15 noviembre, 2025
Compartir
Iniciar sesión dejar un comentario

  
Buenas prácticas CSS modernas: guía completa con ejemplos y casos reales
Descubre las mejores prácticas para escribir CSS moderno, escalable y de alto rendimiento. Incluye ejemplos, comparativas, herramientas de linting, accesibilidad y optimización.