Почему instanceof возвращает false для некоторых литералов?

"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

Литералы массивов и литералы объектов соответствуют...

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

Почему не все? Или, почему они не все? И, каковы они экземпляры, тогда?

Это то же самое в FF3, IE7, Opera и Chrome. Поэтому, по крайней мере, это непротиворечиво.


Пропустили несколько.

12.21 instanceof Number //=> false
/foo/ instanceof RegExp //=> true

Ответы

Ответ 1

Примитивы - это другой тип типа, чем объекты, созданные из Javascript. Из Документы API Mozilla:

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

Я не могу найти способ построить примитивные типы с кодом, возможно, это невозможно. Вероятно, поэтому люди используют typeof "foo" === "string" вместо instanceof.

Легкий способ запомнить такие вещи, спрашивая себя: "Интересно, что было бы разумно и легко учиться"? Каким бы ни был ответ, Javascript делает другое.

Ответ 2

Я использую:

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

Потому что в JavaScript строки могут быть литералами или объектами.

Ответ 3

В JavaScript все является объектом (или, по крайней мере, может рассматриваться как объект), за исключением примитивов (booleans, null, numbers, strings и значение undefined (и символ в 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

Как вы можете видеть объекты, массивы и значение null считаются объектами (null является ссылкой на объект, который не существует). Функции различаются, поскольку они являются особым типом вызываемых объектов. Однако они все еще являются объектами.

С другой стороны, литералы true, 0, "" и undefined не являются объектами. Они являются примитивными значениями в JavaScript. Однако логические значения, числа и строки также имеют конструкторы Boolean, Number и String соответственно, которые обертывают свои соответствующие примитивы для обеспечения добавленной функциональности:

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

Как вы можете видеть, когда примитивные значения обернуты внутри конструкторов Boolean, Number и String соответственно, они становятся объектами. Оператор instanceof работает только для объектов (поэтому он возвращает false для примитивных значений):

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

Как вы можете видеть, как typeof, так и instanceof недостаточно, чтобы проверить, является ли значение логическим, число или строка - typeof работает только для примитивных булевых, чисел и строк; и instanceof не работает для примитивных булевых, чисел и строк.

К счастью, существует простое решение этой проблемы. Реализация по умолчанию toString (т.е. Как она определена на Object.prototype.toString) возвращает внутреннее свойство [[Class]] как примитивных значений, так и объектов:

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]

Внутреннее свойство [[Class]] значения гораздо более полезно, чем значение typeof. Мы можем использовать Object.prototype.toString для создания нашей собственной (более полезной) версии оператора typeof следующим образом:

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

Надеюсь, эта статья помогла. Чтобы узнать больше о различиях между примитивами и обернутыми объектами, прочитайте следующее сообщение в блоге: Секретная жизнь примитивов JavaScript

Ответ 4

Свойство конструктора можно использовать:

'foo'.constructor == String // returns true
true.constructor == Boolean // returns true

Ответ 5

 typeof(text) === 'string' || text instanceof String; 

вы можете использовать это, он будет работать для обоих случаев как

  • var text="foo";//typeof будет работать

  • String text= new String("foo");//instanceof будет работать

Ответ 6

Я считаю, что придумал жизнеспособное решение:

Object.getPrototypeOf('test') === String.prototype    //true
Object.getPrototypeOf(1) === String.prototype         //false

Ответ 7

Я использую это для решения:

function typeOf(value) {
    var ret = typeof value;

    // adjusting type based on object instanceof
    if (ret === 'object') {
        if (value instanceof Date) {
            ret = 'date';
        } else
        if (value instanceof Number) {
            ret = 'number';
        } else
        if (value instanceof String) {
            ret = 'string';
        } else
        if (value instanceof Boolean) {
            ret = 'boolean';
        }
    }
    return ret;
}

Ответ 8

Это определяется в разделе 7.3.19 спецификации ECMAScript. Шаг 3. If Type(O) is not Object, return false.

Другими словами, если объект Obj в Obj instanceof Callable не является объектом, instanceof будет напрямую Obj instanceof Callable на false.

Ответ 9

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

Возвращает строковое представление instanceof (имя конструктора)

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"

Ответ 10

Для меня путаница, вызванная

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

So "str" istanceof String должен возвращать true, потому что как istanceof работает, как показано ниже:

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

Результаты выражения # 1 и # 2 конфликтуют друг с другом, поэтому должен быть один из них неправильный.

# 1 неверно

Я выясню, что это вызвано __proto__ нестандартным свойством, поэтому используйте стандартный: Object.getPrototypeOf

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

Теперь нет путаницы между выражением # 2 и # 3

Ответ 11

Или вы можете просто сделать свою собственную функцию следующим образом:

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

использование:

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

Они должны возвращать true.

Ответ 12

Это потому, что эти вещи являются примитивами, и если они не должны использоваться как объекты (например, когда вы вызываете их на них), они остаются такими. Единственный момент, когда они становятся объектами, - это когда их нужно обернуть. Если вы знакомы с концепцией "бокса" в .NET, подумайте об этом таким образом.

Вот пример - посмотрите на этот код:

Number.prototype.times = function(func) {
   for(var index = 1; index <= this; index++) {
      func(index);
   }
};

Таким образом, следующий код не будет выполнен:

3.times(print); // assume 'print' writes to standard out

3, сам по себе является примитивным. При этом будет работать следующее:

(3).times(print); // assume 'print' writes to standard out

Это отображает числа 1, 2 и 3. Из-за скобки интерпретатор JavaScript временно будет переносить примитив 3 в объект Number, вызывать метод, а затем мусор собирать объект, поскольку он не нужен дольше.

В любом случае, полное обсуждение этого вопроса можно найти в "JavaScript: окончательное руководство."