Nos encontraremos que muchas veces no resulta tan sencillo saber cuál es el tipo de dato de una variable o constante. Por ejemplo, cuando una función devuelve un valor que en principio desconocemos.
Hay varias formas de saber que tipo de dato tiene una variable en Javascript.
El operador typeof
Si tenemos dudas, podemos utilizar la función typeof
, que nos devuelve el tipo de dato primitivo de la variable que le pasemos por parámetro. Veamos que nos devuelve typeof
sobre algunas variables:
const text = "Hola ManzDev!";
typeof text; // Devuelve "String"
const number = 42;
typeof number; // Devuelve "Number"
const boolean = true;
typeof boolean; // Devuelve "Boolean"
let notDefined;
typeof notDefined; // Devuelve undefined
Como se puede ver, mediante la función typeof podremos determinar que tipo de dato se esconde en una variable. Observa también que la variable notDefined
, al haber sido declarada sin valor, Javascript le da un tipo de dato especial: undefined (sin definir).
OJO: La función typeof
no nos servirá para variables con tipos de datos más complejos, ya que siempre los mostrará como object
y no sabremos exactamente el tipo de dato concreto:
const numbers = [1, 2, 3, 4];
typeof numbers; // Devuelve "object"
const user = { name: "ManzDev" };
typeof user; // Devuelve "object"
Como veremos a continuación, para esto puede ser mejor utilizar constructor.name
.
La propiedad constructor.name
En muchos casos, nos encontraremos que typeof
resulta insuficiente porque en tipos de datos más avanzados simplemente nos indica que son objetos, pero no sabes que clase de objeto específico. Con constructor.name
, que es una parte de la Orientación a objetos podemos obtener el tipo de constructor que se utiliza, un concepto que veremos más adelante dentro del tema de clases.
De momento, si lo necesitamos, podemos comprobarlo así:
const text = "Hola ManzDev!";
text.constructor.name; // String
const number = 42;
number.constructor.name; // Number
const boolean = true;
boolean.constructor.name; // Boolean
let notDefined;
notDefined.constructor.name; // ERROR
// constructor.name sólo funciona en variables definidas
const numbers = [1, 2, 3, 4];
numbers.constructor.name; // Array
const user = { name: "ManzDev" };
user.constructor.name; // Object
Observa que en tipo de datos no primitivos, que veremos más adelante, como los arrays, no nos dice object
como hacía el typeof
, sino que nos devuelve específicamente Array
.
Cadena de prototipos
Para entender un poco mejor todo esto, debemos saber que Javascript funciona de modo que cada elemento tiene una cadena de prototipos, esto es, cada elemento hereda de otros elementos. Observa el siguiente ejemplo de código, donde la función getPrototypeChain()
devuelve una lista de prototipos de un elemento pasado por parámetro:
getPrototypeChain("Hola"); // ['String', 'Object', null]
getPrototypeChain(42); // ['Number', 'Object', null]
getPrototypeChain([1, 2, 3]); // ['Array', 'Object', null]
getPrototypeChain(/.+/); // ['RegExp', 'Object', null]
const getPrototypeChain = (object) => {
const chain = [];
let proto = object;
do {
proto = Object.getPrototypeOf(proto);
chain.push(proto?.constructor?.name ?? null);
} while (proto);
return chain;
}
Observa que los prototipos de "Hola"
(un String) son String
, Object
y null
. Esto quiere decir que "Hola"
hereda de los prototipos String
, Object
y null
. Por otro lado, los prototipos de 42
son Number
, Object
y null
. Algunas consideraciones interesantes sobre esto:
- 1️⃣ El primer prototipo es el tipo de dato de la variable. Por ejemplo,
String
en el primer ejemplo. - 2️⃣ Como
String
, puede usar todas las operaciones para(lo veremos más adelante). - 3️⃣ El segundo prototipo es un
Object
, por lo que también puede usar las operaciones de. - 4️⃣ Por último,
null
es el terminador de la cadena de prototipos. Simplemente hemos llegado al final.
El operador instanceof
Ahora que conocemos el concepto de cadena de prototipos también podemos utilizar instanceof
para saber si una variable hereda de uno de los tipos que hemos visto en el apartado anterior. Por ejemplo:
const numbers = [1, 2, 3];
getPrototypeChain(numbers); // ['Array', 'Object', null]
numbers instanceof Array // true
numbers instanceof Object // true
numbers instanceof Number // false
numbers instanceof String // false
Pero al igual que con vimos con typeof
, hay una desventaja. Mientras que typeof
sólo sirve para tipos de datos primitivos, instanceof
sólo sirve para tipos de datos no primitivos.
Recuerda que el hecho de que Javascript determine los tipos de datos automáticamente no quiere decir que no debamos preocuparnos por ello. A menudo, deberemos conocer el tipo de dato de una variable e incluso necesitaremos convertirla a otros tipos de datos. Más adelante veremos formas de convertir entre tipos de datos.