¿Por qué instanceof devuelve false para algunos literales?


"foo" instanceof String //=> false
"foo" instanceof Object //=> false
true instanceof Boolean //=> false
true instanceof Object //=> false
false instanceof Boolean //=> false
false instanceof Object //=> false

// the tests against Object really don't make sense

Los literales de matriz y los literales de objeto coinciden...

[0,1] instanceof Array //=> true
{0:1} instanceof Object //=> true

¿Por qué no todos ellos? O, ¿por qué no todos no?
Y, ¿de qué son un ejemplo, entonces?

Es lo mismo en FF3, IE7, Opera y Chrome. Así que, al menos es consistente.


Se perdieron algunos.

12.21 instanceof Number //=> false
/foo/ instanceof RegExp //=> true
Author: Jonathan Lonowski, 2008-10-15

9 answers

Las primitivas son un tipo de tipo diferente a los objetos creados desde Javascript. Desde el Mozilla API docs :

var color1 = new String("green");
color1 instanceof String; // returns true
var color2 = "coral";
color2 instanceof String; // returns false (color2 is not a String object)

No puedo encontrar ninguna manera de construir tipos primitivos con código, tal vez no sea posible. Esta es probablemente la razón por la que la gente usa typeof "foo" === "string" en lugar de instanceof.

Una manera fácil de recordar cosas como esta es preguntarse "Me pregunto qué sería cuerdo y fácil de aprender"? Cualquiera que sea la respuesta, Javascript hace la otra cosa.

 337
Author: John Millikin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-02-22 21:29:45

Utilizo:

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

Porque en JavaScript las cadenas pueden ser literales u objetos.

 82
Author: axkibe,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-02-26 20:41:26

En JavaScript todo es un objeto (o al menos puede ser tratado como un objeto), excepto primitivas (booleanos, null, 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 arrays y el valor null son todos objetos considerados (null es una referencia a un objeto que no existe). Las funciones se distinguen porque son un tipo especial de objetos llamables. Sin embargo, siguen siendo objetos.

Sobre la 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 respectivas primitivas para proporcionar funcionalidad adicional:

console.log(typeof new Boolean(true)); // object
console.log(typeof new Number(0));     // object
console.log(typeof new String(""));    // object

Como se puede ver cuando los valores primitivos se envuelven dentro de la Boolean, Number y String constructores respectivamente se convierten en objetos. El operador instanceof solo funciona para objetos (por eso devuelve 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 puede ver, tanto typeof como instanceof son insuficientes para probar si un valor es un booleano, un número o una cadena - typeof solo funciona para booleanos primitivos, números y cadenas; y instanceof no funciona para booleanos primitivos, números y cadenas.

Afortunadamente hay una solución simple a este problema. La implementación predeterminada de toString (es decir, como se define de forma nativa en Object.prototype.toString) devuelve la propiedad interna [[Class]] de ambos 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 propiedad interna [[Class]] de un valor es mucho más útil que el typeof el valor. Podemos usar Object.prototype.toString para crear nuestra propia versión (más útil) del operador typeof 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 las primitivas y los objetos envueltos, lea la siguiente publicación del blog: La Vida Secreta de las primitivas de JavaScript

 48
Author: Aadit M Shah,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-01-09 12:26:17

Puede usar la propiedad constructor:

'foo'.constructor == String // returns true
true.constructor == Boolean // returns true
 29
Author: user144049,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-07-26 23:10:50
 typeof(text) === 'string' || text instanceof String; 

Puede usar esto, funcionará para ambos casos como

  1. var text="foo"; // typeof funcionará

  2. String text= new String("foo"); // instanceof funcionará

 6
Author: saurabhgoyal795,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-08-23 11:30:06

Creo que he encontrado una solución viable:

Object.getPrototypeOf('test') === String.prototype    //true
Object.getPrototypeOf(1) === String.prototype         //false
 1
Author: Robby Harris,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-03-19 21:14:10

Https://www.npmjs.com/package/typeof

Devuelve una string-representation de instanceof (el nombre del constructor)

function instanceOf(object) {
  var type = typeof object

  if (type === 'undefined') {
    return 'undefined'
  }

  if (object) {
    type = object.constructor.name
  } else if (type === 'object') {
    type = Object.prototype.toString.call(object).slice(8, -1)
  }

  return type.toLowerCase()
}

instanceOf(false)                  // "boolean"
instanceOf(new Promise(() => {}))  // "promise"
instanceOf(null)                   // "null"
instanceOf(undefined)              // "undefined"
instanceOf(1)                      // "number"
instanceOf(() => {})               // "function"
instanceOf([])                     // "array"
 -1
Author: samdd,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-02-12 01:59:50

Para mí la confusión causada por

"str".__proto__ // #1
=> String

Así que "str" istanceof String debería volver true porque cómo funciona istanceof de la siguiente manera:

"str".__proto__ == String.prototype // #2
=> true

Resultados de la expresión #1 y #2 conflicto entre sí, por lo que debe haber uno de ellos mal.

#1 está mal

Me doy cuenta de que causado por el __proto__ es una propiedad no estándar, así que use la estándar: Object.getPrototypeOf

Object.getPrototypeOf("str") // #3
=> TypeError: Object.getPrototypeOf called on non-object

Ahora no hay confusión entre la expresión #2 y #3

 -2
Author: mko,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-01-12 09:59:50

O simplemente puedes hacer tu propia función así:

function isInstanceOf(obj, clazz){
  return (obj instanceof eval("("+clazz+")")) || (typeof obj == clazz.toLowerCase());
};

Uso:

isInstanceOf('','String');
isInstanceOf(new String(), 'String');

Ambos deben devolver true.

 -7
Author: sth,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-02-17 01:44:34