Лучший способ получить тип переменной Javascript?
есть ли лучший способ получить тип переменной в 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 ответов:
Ангус Кролл недавно написал интересный пост в блоге об этом -
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() }
вы можете попробовать использовать
constructor.name
.[].constructor.name new RegExp().constructor.name
как и во всем JavaScript, кто-то в конечном итоге неизменно указывает, что это как-то зло, поэтому вот ссылка на ответ это покрывает это довольно хорошо.
альтернативой является использование
Object.prototype.toString.call
Object.prototype.toString.call([]) Object.prototype.toString.call(/./)
достаточно хорошая функция захвата типа используется 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, но вы всегда можете добавить больше, изменив
вы можете найти следующую функцию полезности:
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 за уведомление меня: ошибка, обещание, generatorfunction
Также мы можем изменить небольшой пример из ipr101
Object.prototype.toType = function() { return ({}).toString.call(this).match(/\s([a-zA-Z]+)/)[1].toLowerCase() }
и звонок как
"aaa".toType(); // 'string'
одна строка функции:
function type(obj) { return Object.prototype.toString.call(obj).replace(/^\[object (.+)\]$/,"").toLowerCase() }
это дает тот же результат, что и
jQuery.type()
вы можете подать заявку
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¢! действительно, часть причины, по которой я бросаю это здесь, несмотря на длинный список ответов, заключается в том, чтобы предоставить немного больше
all in one
введите решение и получите некоторую обратную связь в будущем о том, как расширить его, чтобы включить большеreal types
.С помощью следующего решения, как уже упоминалось выше, я объединил несколько решений, найденных здесь, а также включил исправить для возврата a значение jQuery на jQuery определенный объект при наличии. Я также добавляю метод к прототипу собственного объекта. Я знаю, что это часто табу, так как это может помешать другим таким расширениям, но я оставляю это
user beware
. Если вам не нравится этот способ, просто скопируйте базовую функцию в любом месте и замените все переменныеthis
с параметром аргумента для передачи (например аргументы[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 аргумент сносно. Если это булевая переменная, отвечающая за
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.
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
и]
но я не уверен, что это истинно в каждом случае.