Typeof в JavaScript на самом деле очень сложен. Его можно использовать для многих вещей, но он также имеет много странного поведения. В этой статье перечислены его многочисленные варианты использования, а также указаны существующие проблемы и решения.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/typeof?redirectlocale=en-US&redirectslug=JavaScript%2FReference%2FOperators%2Ftypeof
> тип не определен
'неопределенный'
> typeof null // известная ошибка
'объект'
> типа правда
'логическое'
>тип 123
'число'
> типа "abc"
'нить'
> функция типа() {}
'функция'
> тип {}
'объект'
>тип[]
'объект'
> тип неизвестной переменной
'неопределенный'
1. Проверьте, существует ли переменная и имеет ли она значение.
typeof вернет «неопределенное» в двух ситуациях: когда переменная не объявлена и когда значение переменной не определено. Например:
> typeof необъявленная переменная === "неопределено" true > var объявленная переменная > typeof объявленная переменная 'неопределено' > typeof неопределено 'неопределено';
Существуют и другие способы определить, является ли значение неопределенным:
> значение var = неопределенное > значение === неопределенное true;
Но если этот метод используется для необъявленной переменной, будет выдано исключение, поскольку только typeof может нормально обнаруживать необъявленные переменные, не сообщая об ошибке:
> необъявленная переменная === неопределенная ReferenceError: необъявленная переменная не определена
Примечание. Неинициализированные переменные, формальные параметры без переданных параметров и несуществующие свойства не будут иметь вышеуказанных проблем, поскольку они всегда доступны, а значение всегда неопределенное:
> var объявленная переменная; > объявленная переменная === неопределенная истина > (функция (x) { return x === неопределенная }()) истина > ({}).foo === неопределенная истина
Примечание переводчика: поэтому, если вы хотите обнаружить существование глобальной переменной, которая не может быть объявлена, вы также можете использовать if(window.maybeUndeclaredVariable){}
Проблема: typeof слишком громоздок для решения такой задачи.
Решение: Такая операция не очень распространена, поэтому некоторые считают, что нет необходимости искать лучшее решение. Но, возможно, кто-то предложит специальный оператор:
> определена необъявленная переменная false > var объявленная переменная > определена объявленная переменная false;
Или, может быть, еще нужен оператор, который определяет, объявлена ли переменная:
> объявленная необъявленная переменная false > var объявленная переменная > объявленная объявленная переменная true;
Примечание переводчика: В Perl определенный выше оператор эквивалентен define(), а объявленный выше оператор эквивалентен существует().
2. Определите, не равно ли значение неопределенному или нулевому значению.
Проблема: Если вы хотите проверить, определено ли значение (это значение не является ни неопределенным, ни нулевым), то вы столкнетесь с одной из самых известных особенностей typeof (считающейся ошибкой): typeof null возвращает «объект»:
> тип нулевого 'объекта'
Примечание переводчика: это можно назвать ошибкой только в исходной реализации JavaScript, и именно так теперь стандартизируется стандарт V8, когда он был пересмотрен и реализован typeof null === "null", но в конечном итоге это оказалось невозможным http: //wiki .ecmascript.org/doku.php?id=harmony:typeof_null
Решение. Не используйте typeof для этой задачи, вместо этого используйте такую функцию:
function isDefined(x) { return x !== null && x !== undefined };
Другая возможность — ввести «оператор значения по умолчанию», где следующее выражение возвращает defaultValue, если myValue не определено:
мое значение ?? значение по умолчанию
Вышеприведенное выражение эквивалентно:
(myValue !== неопределенное && myValue !== null) ?
Или:
myValue ??= значение по умолчанию
По сути, это упрощение следующего утверждения:
моеЗначение = моеЗначение ??
При доступе к вложенному свойству, например bar, вам может понадобиться помощь этого оператора:
obj.foo.bar
Если obj или obj.foo не определены, приведенное выше выражение выдаст исключение. Оператор.?? позволяет приведенному выше выражению вернуть первое значение, обнаруженное при обходе свойств слой за слоем. Свойства, которые не определены или имеют значение NULL:
объект.??foo.??бар
Вышеприведенное выражение эквивалентно:
(obj === неопределенное || obj === null) ? obj : (obj.foo === неопределенное || obj.foo === null) ? obj.foo : obj.foo.bar
3. Различайте значения объекта и значения примитива.
Следующая функция проверяет, является ли x значением объекта:
function isObject(x) { return (typeof x === "функция" || (typeof x === "объект" && x !== null) });
Проблема: описанное выше обнаружение сложно, поскольку typeof рассматривает функции и объекты как разные типы, а typeof null возвращает «объект».
Решение. Для определения значений объекта также часто используется следующий метод:
функция isObject2(x) { return x === Object(x) };
Предупреждение. Вы можете подумать, что для обнаружения здесь можно использовать экземпляр объекта, но экземпляр экземпляра определяет отношение экземпляра, используя прототип объекта, а как насчет объектов без прототипов:
> вар obj = Object.create(null) > Object.getPrototypeOf(obj) null);
obj действительно является объектом, но не экземпляром какого-либо значения:
> typeof obj 'object' > obj instanceof Object false
На практике вы редко встретите такой объект, но он существует и имеет свое применение.
Примечание переводчика: Object.prototype — это объект, который существует по умолчанию и не имеет прототипа.
>Object.getPrototypeOf(Object.prototype)null>typeof Object.prototype'object'>Object.prototype экземпляр объекта false
4.Какой тип примитивного значения?
typeof — лучший способ проверить тип примитивного значения.
> typeof "abc" 'строка' > typeof undef 'unопределенный'
Проблема: вы, должно быть, знаете о странном поведении typeof null.
> typeof null // Будьте осторожны, 'объект'
Решение. Следующая функция может решить эту проблему (только для этого варианта использования).
function getPrimitiveTypeName(x) { var typeName = typeof x; switch(typeName) { случай "неопределенный": случай "логический": случай "номер": случай "строка": возвращаемый типИмя; случай "объект": if (x == = null) { return "null" } default: // Ни одно из предыдущих решений не было принято throw new TypeError("Параметр не является примитивным значением: "+x);
Лучшее решение: реализовать функцию getTypeName(), которая помимо возврата типа исходного значения может также возвращать внутренний атрибут [[Class]] значения объекта. Вот как реализовать эту функцию (Примечание переводчика: jQuery $.type — такая реализация)
5. Является ли определенное значение функцией
typeof можно использовать для определения того, является ли значение функцией. > typeof function () {} 'function' > typeof Object.prototype.toString 'function'.
В принципе, экземпляр Функция также может обнаружить это требование. На первый взгляд кажется, что метод записи более элегантен. Однако у браузера есть особенность: каждый фрейм и окно имеют свои глобальные переменные. Поэтому, если вы поместите определенный фрейм в If. объект передается в другую платформу, instanceof не будет работать должным образом, поскольку обе платформы имеют разные конструкторы. Вот почему в ECMAScript 5 есть метод Array.isArray(). Было бы неплохо, если бы существовал межплатформенный метод для проверки того, является ли объект экземпляром заданного конструктора. Вышеупомянутый метод getTypeName() является доступным обходным решением. , но может быть более фундаментальное решение.
6.Обзор
Следующие упомянутые функции должны быть наиболее необходимыми в настоящее время в JavaScript и могут заменить некоторые функциональные возможности текущих обязанностей typeof:
isDefined() (например, Object.isDefined()): может использоваться как функция или оператор.
isObject()
getTypeName()
Межплатформенный механизм определения того, является ли объект экземпляром указанного конструктора.
Необходимость проверки того, была ли объявлена переменная, может не требовать наличия собственного оператора.