Лучший способ получить тип переменной Javascript? - PullRequest
238 голосов
/ 12 сентября 2011

Есть ли лучший способ получить тип переменной в JS, чем typeof? Он отлично работает, когда вы делаете:

> typeof 1
"number"
> typeof "hello"
"string"

Но это бесполезно, когда вы пытаетесь:

> typeof [1,2]
"object"
>r = new RegExp(/./)
/./
> typeof r
"function"

Я знаю о instanceof, но это требует, чтобы вы знали тип заранее.

> [1,2] instanceof Array
true
> r instanceof RegExp
true

Есть ли лучший способ?

Ответы [ 9 ]

207 голосов
/ 12 сентября 2011

Ангус Кролл недавно написал интересный пост в блоге об этом -

http://javascriptweblog.wordpress.com/2011/08/08/fixing-the-javascript-typeof-operator/

Он анализирует плюсы и минусы различных методов, затем определяет новый метод toType -

var toType = function(obj) {
  return ({}).toString.call(obj).match(/\s([a-zA-Z]+)/)[1].toLowerCase()
}
47 голосов
/ 12 сентября 2011

Вы можете попробовать использовать constructor.name.

[].constructor.name
new RegExp().constructor.name

Как и во всем JavaScript, кто-то в конце концов неизменно укажет, что это как-то зло, поэтому здесь есть ссылка на ответ это достаточно хорошо.

Альтернативой является использование Object.prototype.toString.call

Object.prototype.toString.call([])
Object.prototype.toString.call(/./)
38 голосов
/ 12 сентября 2011

Достаточно хорошей функцией захвата типа является та, которая используется YUI3 :

var TYPES = {
    'undefined'        : 'undefined',
    'number'           : 'number',
    'boolean'          : 'boolean',
    'string'           : 'string',
    '[object Function]': 'function',
    '[object RegExp]'  : 'regexp',
    '[object Array]'   : 'array',
    '[object Date]'    : 'date',
    '[object Error]'   : 'error'
},
TOSTRING = Object.prototype.toString;

function type(o) {
    return TYPES[typeof o] || TYPES[TOSTRING.call(o)] || (o ? 'object' : 'null');
};

Это захватывает многие из примитивов, предоставляемых javascript, но вы всегда можете добавить больше, изменив объект TYPES. Обратите внимание, что typeof HTMLElementCollection в Safari сообщит function, но тип (HTMLElementCollection) вернет object

25 голосов
/ 12 февраля 2015

Может оказаться полезной следующая функция:

function typeOf(obj) {
  return {}.toString.call(obj).split(' ')[1].slice(0, -1).toLowerCase();
}

Или в ES7 (прокомментируйте, если дальнейшие улучшения)

function typeOf(obj) {
  const { toString } = Object.prototype;
  const stringified = obj::toString();
  const type = stringified.split(' ')[1].slice(0, -1);

  return type.toLowerCase();
}

Результаты:

typeOf(); //undefined
typeOf(null); //null
typeOf(NaN); //number
typeOf(5); //number
typeOf({}); //object
typeOf([]); //array
typeOf(''); //string
typeOf(function () {}); //function
typeOf(/a/) //regexp
typeOf(new Date()) //date
typeOf(new Error) //error
typeOf(Promise.resolve()) //promise
typeOf(function *() {}) //generatorfunction
typeOf(new WeakMap()) //weakmap
typeOf(new Map()) //map

Спасибо @johnrees за то, что сообщили мне об ошибке, обещании, функции генератора

14 голосов
/ 08 ноября 2012

Также мы можем изменить маленький пример с ipr101

Object.prototype.toType = function() {
  return ({}).toString.call(this).match(/\s([a-zA-Z]+)/)[1].toLowerCase()
}

и назвать как

"aaa".toType(); // 'string'
8 голосов
/ 31 октября 2012

функция одной строки:

function type(obj) {
    return Object.prototype.toString.call(obj).replace(/^\[object (.+)\]$/,"$1").toLowerCase()
}

это дает тот же результат, что и jQuery.type()

3 голосов
/ 09 июля 2016

Мои 2 ¢! На самом деле, одна из причин, по которой я здесь это бросаю, несмотря на длинный список ответов, заключается в том, чтобы предоставить немного больше all in one введите решение и получите обратную связь в будущем о том, как расширить его, чтобы включить больше real types.

С помощью следующего решения, как было упомянуто выше, я объединил пару найденных здесь решений, а также включил исправление для возврата значения jQuery в jQuery определенный объект , если доступен . Я также добавляю метод к собственному прототипу Object. Я знаю, что это часто табу, поскольку оно может мешать другим подобным расширениям, но я оставляю это на user beware. Если вам не нравится этот способ, просто скопируйте базовую функцию куда угодно и замените все переменные this на параметр аргумента для передачи (например, arguments [0]).

;(function() {  //  Object.realType
    function realType(toLower) {
        var r = typeof this;
        try {
            if (window.hasOwnProperty('jQuery') && this.constructor && this.constructor == jQuery) r = 'jQuery';
            else r = this.constructor && this.constructor.name ? this.constructor.name : Object.prototype.toString.call(this).slice(8, -1);
        }
        catch(e) { if (this['toString']) r = this.toString().slice(8, -1); }
        return !toLower ? r : r.toLowerCase();
    }
    Object['defineProperty'] && !Object.prototype.hasOwnProperty('realType')
        ? Object.defineProperty(Object.prototype, 'realType', { value: realType }) : Object.prototype['realType'] = realType;
})();

Тогда просто используйте с легкостью, вот так:

obj.realType()  //  would return 'Object'
obj.realType(true)  //  would return 'object'

Примечание: Передается 1 аргумент. Если значение bool равно true, возврат всегда будет в в нижнем регистре .

Больше примеров:

true.realType();                            //  "Boolean"
var a = 4; a.realType();                    //  "Number"
$('div:first').realType();                   // "jQuery"
document.createElement('div').realType()    //  "HTMLDivElement"

Если у вас есть что добавить, что может быть полезным, например, определение того, когда объект был создан с помощью другой библиотеки (Moo, Proto, Yui, Dojo и т. Д.), Пожалуйста, не стесняйтесь комментировать или редактировать это и продолжать в том же духе быть более точным и точным. ИЛИ перевернитесь на GitHub Я сделал для этого и дайте мне знать. Там же вы найдете быструю ссылку на файл cdn min.

3 голосов
/ 12 сентября 2011

Вы можете применить Object.prototype.toString к любому объекту:

var toString = Object.prototype.toString;

console.log(toString.call([]));
//-> [object Array]

console.log(toString.call(/reg/g));
//-> [object RegExp]

console.log(toString.call({}));
//-> [object Object]

Это хорошо работает во всех браузерах, за исключением IE - при вызове этого для переменной, полученной из другого окна, он просто выплюнет[object Object].

2 голосов
/ 06 июня 2016
function getType(obj) {
    if(obj && obj.constructor && obj.constructor.name) {
        return obj.constructor.name;
    }
    return Object.prototype.toString.call(obj).slice(8, -1).toLowerCase();
}

В моих предварительных тестах это работает довольно хорошо.В первом случае будет напечатано имя любого объекта, созданного с помощью «new», а во втором случае должно быть поймано все остальное.

Я использую (8, -1), потому что я предполагаю, что результат всегда будетначинать с [object и заканчивать ], но я не уверен, что это так в каждом сценарии.

...