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