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.
Averiguar el tipo de dato
Hay varias formas de saber que tipo de dato tiene una variable en Javascript. Las dos principales: typeof
y constructor.name
.
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), que mencionamos en el tema anterior.
Todo esto son variables o constantes que tienen información almacenada mediante tipos de datos primitivos. La función
typeof
nos servirá para diferenciar si se trata de una estructura de datos primitiva o de una estructura de datos no primitiva (objetos más complejos).
Sin embargo, typeof
no nos servirá para diferenciar exactamente de que tipo de dato complejo se trata, ya que los mostrará siempre como object
y no sabremos exactamente de cual se trata:
const numbers = [1, 2, 3, 4];
typeof numbers; // Devuelve "object"
const user = { name: "ManzDev" };
typeof user; // Devuelve "object"
En este ejemplo tenemos dos estructuras más complejas que veremos más adelante: un array y un objeto (ahora no es importante). Simplemente, observa que en ambos casos nos dice que es un object
. No diferencia entre ellos.
Como veremos a continuación, para esto puede ser mejor utilizar constructor.name
.
La propiedad constructor.name
Como hemos visto, 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
.
Objetos envolventes
Si eres una persona observadora, en la pestaña anterior probablemente te habrás fijado en algo muy sutil a la hora de comprobar el tipo de dato:
const text = "Hola";
typeof text // "string"
text.constructor.name // "String"
No devuelve exactamente lo mismo. En el primer caso con typeof
devuelve string
(en minúsculas) y en el caso de constructor.name
devuelve String
(en mayúsculas).
Quizás así lo veas más claro:
const primitive = "Manz"; // En este caso, tenemos un primitivo
const nonprimitive = new String("Manz"); // En este caso, tenemos un objeto
console.log("Hola " + primitive); // "Hola Manz"
console.log("Hola " + nonprimitive); // "Hola Manz"
A grandes rasgos es lo mismo, pero internamente hay diferencias. Este comportamiento en Javascript se llama autoboxing.
Más sobre el autoboxing
En el ejemplo anterior, en el primer caso tenemos una constante primitive
que contiene un tipo de dato primitivo directamente. Sin embargo, en el segundo caso de la constante nonprimitive
, tenemos un objeto que no es primitivo: un objeto String
que «envuelve» al primitivo:
primitive // "Manz"
nonprimitive // String { "Manz" }
typeof primitive // "string"
typeof nonprimitive // "object"
Aunque son elementos diferentes, actúan casi siempre de forma muy similar. Internamente, Javascript convierte los primitivos en objetos para utilizarlos de forma adecuada, con sus métodos y propiedades.