Em JavaScript, tudo é um objeto (ou pelo menos pode ser tratado como um objeto), exceto primitivas (booleanos, nulos, números, seqüências de caracteres e o valor undefined
(e símbolo no 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 você pode ver objetos, matrizes e o valor null
são todos considerados objetos ( null
é uma referência a um objeto que não existe). As funções são diferenciadas porque são um tipo especial de objetos que podem ser chamados . No entanto, eles ainda são objetos.
Por outro lado, os literais true
, 0
, ""
e undefined
não são objetos. Eles são valores primitivos em JavaScript. No entanto, booleanos, números e seqüências de caracteres também têm construtores e Boolean
, respectivamente, que agrupam suas respectivas primitivas para fornecer funcionalidade adicional:Number
String
console.log(typeof new Boolean(true)); // object
console.log(typeof new Number(0)); // object
console.log(typeof new String("")); // object
Como você pode ver quando os valores primitivos são agrupados nos construtores Boolean
, Number
e String
respectivamente eles se tornam objetos. O instanceof
operador trabalha apenas para objetos (é por isso que retorna false
para 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 você pode ver os dois typeof
e instanceof
é insuficiente para testar se um valor é um booleano, um número ou uma string - typeof
funciona apenas para booleanos primitivos, números e strings; e instanceof
não funciona para booleanos primitivos, números e seqüências de caracteres.
Felizmente, existe uma solução simples para esse problema. A implementação padrão de toString
(ou seja, como é definida originalmente Object.prototype.toString
) retorna a [[Class]]
propriedade interna dos valores e 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]
A [[Class]]
propriedade interna de um valor é muito mais útil que typeof
o valor. Podemos usar Object.prototype.toString
para criar nossa própria versão (mais útil) do typeof
operador da seguinte maneira:
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 artigo tenha ajudado. Para saber mais sobre as diferenças entre objetos primitivos e agrupados, leia a seguinte postagem no blog: A Vida Secreta das Primitivas JavaScript