Почему 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;
вы можете использовать это, он будет работать для обоих случаев как
Ответ 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: окончательное руководство."