Почему instanceof возвращает false для некоторых литералов?
-
03-07-2019 - |
Вопрос
"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
Решение
Примитивы — это другой тип типов, чем объекты, созданные в 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 делает другое.
Другие советы
Я использую:
function isString(s) {
return typeof(s) === 'string' || s instanceof String;
}
Потому что в JavaScript строки могут быть литералами или объектами.
В JavaScript все является объектом (или, по крайней мере, может рассматриваться как объект), за исключением примитивы (логические значения, ноль, числа, строки и значение 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
Вы можете использовать свойство конструктора:
'foo'.constructor == String // returns true
true.constructor == Boolean // returns true
typeof(text) === 'string' || text instanceof String;
вы можете использовать это, оно будет работать в обоих случаях как
var text="foo";
// typeof будет работатьString text= new String("foo");
// экземпляр будет работать
Я считаю, что нашел жизнеспособное решение:
Object.getPrototypeOf('test') === String.prototype //true
Object.getPrototypeOf(1) === String.prototype //false
Это определено в спецификации ECMAScript. Раздел 7.3.19 Шаг 3: If Type(O) is not Object, return false.
Другими словами, если Obj
в Obj instanceof Callable
не является объектом, instanceof
произойдет короткое замыкание на false
напрямую.
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"
Для меня путаница, вызванная
"str".__proto__ // #1
=> String
Так "str" istanceof String
должен вернуться true
потому что isstanceof работает, как показано ниже:
"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
Или вы можете просто создать свою собственную функцию следующим образом:
function isInstanceOf(obj, clazz){
return (obj instanceof eval("("+clazz+")")) || (typeof obj == clazz.toLowerCase());
};
Применение:
isInstanceOf('','String');
isInstanceOf(new String(), 'String');
Оба они должны вернуть true.