5

Es decir, cómo se puede ver en el ejemplo de abajo, el prototipo de todos los objetos dados es de tipo Number, pero si se realiza un:

const obj = 9;

obj instanceof Number // false

sin haberlo pasado por un

new Number(obj) instanceof Number // true

Siempre devolverá false, ejemplos:

var is = Function.prototype.call.bind(Object.prototype.toString);
var log = console.log.bind(console);
const num = 9;

log(typeof(9));                         // number
log(is(9));                             // [object Number]
log(9 instanceof Number);               // false
log('');

log(typeof(num));                       // number
log(is(num));                           // [object Number]
log(num instanceof Number);             // false
log('');

log(typeof(new Number(9)));             // object
log(is(new Number(9)));                 // [object Number]
log(new Number(9) instanceof Number);   // true
log('');

log(typeof(new Number(num)));           // object
log(is(new Number(num)));               // [object Number]
log(new Number(num) instanceof Number); // true

¿Por qué sucede esto?

Jorius
  • 6,109
  • 9
  • 28
  • 55

2 Answers2

3

El problema es que no todo valor en javascript es un objeto, también pueden ser primitivos (comúnmente llamados literales), y, según la especificación, instanceof verifica solamente que un valor sea una instancia (objeto) de cierto tipo: en otras palabras, que haya sido inicializado mediante new Tipo.

Por eso es común hacer este tipo de evaluaciones en javascript:

function isString(s) {
  return typeof(s) === 'string' || s instanceof String;
}

Porque una cadena puede ser un valor primitivo o una instancia de la clase String.

Fer García
  • 456
  • 3
  • 10
  • en tu functión nunca se cumplirá el `|| s instanceof String` porque como tu dices `instanceof` verifica solamente que el valor dado haya sido inicializado mediante `new Tipo`, si se le pasa a dicha función un `new String('my string')` devolverá false porque el `typeof` de lo anterior será un `object` y `s instanceof String` devolverá `false` – Jorius Mar 21 '17 at 15:18
  • [¿Lo probaste?](https://jsbin.com/vomahaliqi/edit?js,console) – Fer García Mar 21 '17 at 15:29
  • si lo probé, quizá no supe como hacerme entender, me refiero a que me parece una mala validaciónm porque el `typeof` de un `new Tipo()` siempre será `object` – Jorius Mar 21 '17 at 15:34
  • El punto es que la validación funciona para probar que cierto elemento sea una cadena (o, con su variación, algún otro tipo primitivo que pueda o no ser _wrappable_) independientemente de su forma de inicialización; las [guías de mejores prácticas](https://github.com/airbnb/javascript) para escribir JavaScript no evitan la inicialización de valores simples con _wrappers_ (es decir, `new Tipo`), por lo tanto hay que recurrir a este tipo de "trucos" para probar cualquier caso (si queremos ser estrictos y si, seguramente, estamos integrando código de más de una fuente). – Fer García Mar 21 '17 at 16:18
  • 1
    Te recomiendo leer [esto](https://javascriptweblog.wordpress.com/2010/09/27/the-secret-life-of-javascript-primitives/) (en inglés): me ayudó a entender el tema de los valores primitivos y, además, entender porqué, a pesar que _un valor primitivo no es un objeto_, puedas ejecutar cosas como `"hola mundo".length`. ¡Básicamente es una de las "excentricidades" de JavaScript! – Fer García Mar 21 '17 at 16:24
1

De la página instanceof en la MDN:

Debe especificar un objeto en el lado derecho del operador instanceof. Por ejemplo, puede especificar una cadena creada con el constructor String, pero no puede especificar un literal de cadena.

Es decir, instanceof solo funciona con objetos; por lo tanto, quedan excluidos los tipos primitivos: números, cadenas, true, false, ...

Trauma
  • 25,297
  • 4
  • 37
  • 60