En JavaScript todo es un objeto (o al menos puede tratarse como un objeto), excepto las primitivas (booleanos, nulos, números, cadenas y el valor undefined
(y símbolo en ES6)):
console.log(typeof true); // boolean
console.log(typeof 0); // number
console.log(typeof ""); // string
console.log(typeof undefined); // undefined
console.log(typeof null); // object
console.log(typeof []); // object
console.log(typeof {}); // object
console.log(typeof function () {}); // function
Como puede ver, los objetos, las matrices y el valor null
se consideran objetos ( null
es una referencia a un objeto que no existe). Las funciones se distinguen porque son un tipo especial de objetos invocables . Sin embargo, siguen siendo objetos.
Por otro lado los literales true
, 0
, ""
y undefined
no son objetos. Son valores primitivos en JavaScript. Sin embargo, los booleanos, los números y las cadenas también tienen constructores Boolean
, Number
y String
respectivamente, que envuelven sus primitivas respectivas para proporcionar una funcionalidad adicional:
console.log(typeof new Boolean(true)); // object
console.log(typeof new Number(0)); // object
console.log(typeof new String("")); // object
Como puede ver cuando los valores primitivos se envuelven dentro de Boolean
, Number
y los String
constructores, respectivamente, se convierten en objetos. El instanceof
operador solo funciona para objetos (por lo que devuelve false
valores primitivos):
console.log(true instanceof Boolean); // false
console.log(0 instanceof Number); // false
console.log("" instanceof String); // false
console.log(new Boolean(true) instanceof Boolean); // true
console.log(new Number(0) instanceof Number); // true
console.log(new String("") instanceof String); // true
Como puede ver ambos typeof
y instanceof
no son suficientes para probar si un valor es un valor booleano, un número o una cadena, typeof
solo funciona para booleanos, números y cadenas primitivos; y instanceof
no funciona para booleanos, números y cadenas primitivos.
Afortunadamente, hay una solución simple para este problema. La implementación predeterminada de toString
(es decir, como se define de forma nativa Object.prototype.toString
) devuelve la [[Class]]
propiedad interna de los valores y objetos primitivos:
function classOf(value) {
return Object.prototype.toString.call(value);
}
console.log(classOf(true)); // [object Boolean]
console.log(classOf(0)); // [object Number]
console.log(classOf("")); // [object String]
console.log(classOf(new Boolean(true))); // [object Boolean]
console.log(classOf(new Number(0))); // [object Number]
console.log(classOf(new String(""))); // [object String]
La [[Class]]
propiedad interna de un valor es mucho más útil que typeof
el valor. Podemos usar Object.prototype.toString
para crear nuestra propia versión (más útil) del typeof
operador de la siguiente manera:
function typeOf(value) {
return Object.prototype.toString.call(value).slice(8, -1);
}
console.log(typeOf(true)); // Boolean
console.log(typeOf(0)); // Number
console.log(typeOf("")); // String
console.log(typeOf(new Boolean(true))); // Boolean
console.log(typeOf(new Number(0))); // Number
console.log(typeOf(new String(""))); // String
Espero que este artículo haya ayudado. Para saber más sobre las diferencias entre los primitivos y los objetos envueltos, lea la siguiente publicación de blog: La vida secreta de los primitivos de JavaScript