Проверить, является ли объект массивом?
Я пытаюсь написать функцию, которая либо принимает список строк, либо одну строку. Если это строка, то я хочу преобразовать ее в массив только с одним элементом. Тогда я могу зациклиться на нем, не опасаясь ошибки.
Итак, как мне проверить, является ли переменная массивом?
Я рассмотрел различные решения ниже и создал тест jsperf.
- 1
- 2
В современных браузерах вы можете сделать
Array.isArray(obj)
(Поддерживается Chrome 5, Firefox 4.0, IE 9, Opera 10.5 и Safari 5)
Для обратной совместимости вы можете добавить следующие
# only implement if no native implementation is available
if (typeof Array.isArray === 'undefined') {
Array.isArray = function(obj) {
return Object.prototype.toString.call(obj) === '[object Array]';
}
};
Если вы используете jQuery, вы можете использовать jQuery.isArray(obj)
или $.isArray(obj)
. Если вы используете подчеркивание, вы можете использовать _.isArray(obj)
Если вам не нужно обнаруживать массивы, созданные в разных кадрах, вы также можете просто использовать instanceof
obj instanceof Array
Метод, указанный в стандарте ECMAScript для поиска класса Object, заключается в использовании метода toString
из Object.prototype
.
if( Object.prototype.toString.call( someVar ) === '[object Array]' ) {
alert( 'Array!' );
}
Или вы можете использовать typeof
для проверки, является ли это строкой:
if( typeof someVar === 'string' ) {
someVar = [ someVar ];
}
Или, если вас не интересует производительность, вы можете просто сделать concat
для нового пустого массива.
someVar = [].concat( someVar );
Там также конструктор, который вы можете запросить напрямую:
if (somevar.constructor.name == "Array") {
// do something
}
Ознакомьтесь с подробным описанием блога @TJ Crowder, опубликованным в его комментарии ниже.
Ознакомьтесь с этим эталоном, чтобы получить представление о том, какой метод работает лучше: http://jsben.ch/#/QgYAV
Из @Bharath конвертировать строку в массив с использованием Es6 для заданного вопроса:
const convertStringToArray = (object) => {
return (typeof object === 'string') ? Array(object) : object
}
предположим:
let m = 'bla'
let n = ['bla','Meow']
let y = convertStringToArray(m)
let z = convertStringToArray(n)
console.log('check y: '+JSON.stringify(y)) . // check y: ['bla']
console.log('check y: '+JSON.stringify(z)) . // check y: ['bla','Meow']
Я бы сначала проверил, поддерживает ли ваша реализация isArray
:
if (Array.isArray)
return Array.isArray(v);
Вы также можете попробовать использовать оператор instanceof
v instanceof Array
jQuery также предлагает метод $.isArray()
:
var a = ["A", "AA", "AAA"];
if($.isArray(a)) {
alert("a is an array!");
} else {
alert("a is not an array!");
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
Это самый быстрый среди всех методов (поддерживаются все браузеры):
function isArray(obj){
return !!obj && obj.constructor === Array;
}
Представьте, что у вас есть этот массив ниже:
var arr = [1,2,3,4,5];
Javascript (новые и старые браузеры):
function isArray(arr) {
return arr.constructor.toString().indexOf("Array") > -1;
}
или
function isArray(arr) {
return arr instanceof Array;
}
или
function isArray(arr) {
return Object.prototype.toString.call(arr) === '[object Array]';
}
затем назовите его так:
isArray(arr);
Javascript (IE9+, Ch5+, FF4+, Saf5+, Opera10. 5+)
Array.isArray(arr);
JQuery:
$.isArray(arr);
Угловой:
angular.isArray(arr);
Подчеркивание и Lodash:
_.isArray(arr);
Array.isArray работает быстро, но не поддерживается всеми версиями браузеров. Таким образом, вы можете сделать исключение для других и использовать универсальный метод:
Utils = {};
Utils.isArray = ('isArray' in Array) ?
Array.isArray :
function (value) {
return Object.prototype.toString.call(value) === '[object Array]';
}
Простая функция для проверки:
function isArray(object)
{
if (object.constructor === Array) return true;
else return false;
}
Вы можете попробовать этот подход: http://web.archive.org/web/20100424091244/http://www.ajaxdr.com/code/javascript-version-of-phps-is_array-function/
EDIT: также, если вы уже используете JQuery в своем проекте, вы можете использовать его функцию $. isArray().
Только одно линейное решение для этого вопроса
x instanceof Array
где x - это переменная, она вернет true, если x - массив, а false - если нет.
Поскольку MDN говорит здесь:
используйте Array.isArray или Object.prototype.toString.call, чтобы различать регулярные объекты из массивов
Вот так:
-
Object.prototype.toString.call(arr) === '[object Array]'
, или -
Array.isArray(arr)
Я бы сделал функцию для проверки типа объекта, с которым вы имеете дело...
function whatAmI(me){ return Object.prototype.toString.call(me).split(/\W/)[2]; }
// tests
console.log(
whatAmI(["aiming","@"]),
whatAmI({living:4,breathing:4}),
whatAmI(function(ing){ return ing+" to the global window" }),
whatAmI("going to do with you?")
);
// output: Array Object Function String
тогда вы можете написать простую инструкцию if...
if(whatAmI(myVar) === "Array"){
// do array stuff
} else { // could also check `if(whatAmI(myVar) === "String")` here to be sure
// do string stuff
}
Вы можете проверить тип переменной, является ли она массивом:
var myArray=[];
if(myArray instanceof Array)
{
....
}
Я делаю это очень просто. Работает на меня. Любые недостатки?
Array.prototype.isArray = true;
a=[]; b={};
a.isArray // true
b.isArray // (undefined -> false)
Это моя попытка улучшить этот ответ с учетом комментариев:
var isArray = myArray && myArray.constructor === Array;
Он избавляется от if/else и учитывает возможность того, что массив равен null или undefined
Я обновил скрипт jsperf с помощью двух альтернативных методов, а также проверки ошибок.
Оказывается, метод, определяющий постоянное значение в прототипах "Объект" и "Массив", быстрее, чем любой другой метод. Это несколько удивительный результат.
/* Initialisation */
Object.prototype.isArray = function() {
return false;
};
Array.prototype.isArray = function() {
return true;
};
Object.prototype._isArray = false;
Array.prototype._isArray = true;
var arr = ["1", "2"];
var noarr = "1";
/* Method 1 (function) */
if (arr.isArray()) document.write("arr is an array according to function<br/>");
if (!noarr.isArray()) document.write("noarr is not an array according to function<br/>");
/* Method 2 (value) - **** FASTEST ***** */
if (arr._isArray) document.write("arr is an array according to member value<br/>");
if (!noarr._isArray) document.write("noarr is not an array according to member value<br/>");
Эти два метода не работают, если переменная принимает значение undefined, но они работают, если вы уверены, что они имеют значение. Что касается проверки с учетом производительности, если значение представляет собой массив или одно значение, второй метод выглядит как действительный быстрый метод. Он немного быстрее, чем "экземпляр" в Chrome, в два раза быстрее, чем второй лучший метод в Internet Explorer, Opera и Safari (на моей машине).
https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array/isArray
Array.isArray = Array.isArray || function (vArg) {
return Object.prototype.toString.call(vArg) === "[object Array]";
};
Я знаю, что люди ищут какой-то оригинальный javascript подход. Но если вы хотите меньше думать, посмотрите здесь: http://underscorejs.org/#isArray
_.isArray(object)
Возвращает true, если объект является массивом.
(function(){ return _.isArray(arguments); })();
=> false
_.isArray([1,2,3]);
=> true
Вы можете использовать метод isArray, но я бы предпочел проверить
Object.getPrototypeOf(yourvariable) === Array.prototype
Вот мой ленивый подход:
if (Array.prototype.array_ === undefined) {
Array.prototype.array_ = true;
}
// ...
var test = [],
wat = {};
console.log(test.array_ === true); // true
console.log(wat.array_ === true); // false
Я знаю, что это святотатство "запутаться" с прототипом, но он выглядит значительно лучше, чем рекомендуемый метод toString
.
Примечание. Ловушка этого подхода заключается в том, что не работает через границы iframe
, но для моего это не проблема.
В книге Стояна Стефанова есть хороший пример JavaScript Patterns, который предполагает обработку всех возможных проблем, а также использует метод Array.isArray() ECMAScript 5.
Итак, вот оно:
if (typeof Array.isArray === "undefined") {
Array.isArray = function (arg) {
return Object.prototype.toString.call(arg) === "[object Array]";
};
}
Кстати, если вы используете jQuery, вы можете использовать его метод $.isArray()
Лучшее решение, которое я видел, это кросс-браузерная замена для typeof. Проверьте решение Angus Croll здесь.
Версия TL; DR приведена ниже, но статья - отличное обсуждение проблемы, поэтому вы должны ее прочитать, если у вас есть время.
Object.toType = function(obj) {
return ({}).toString.call(obj).match(/\s([a-z|A-Z]+)/)[1].toLowerCase();
}
// ... and usage:
Object.toType([1,2,3]); //"array" (all browsers)
// or to test...
var shouldBeAnArray = [1,2,3];
if(Object.toType(shouldBeAnArray) === 'array'){/* do stuff */};
Самый простой и быстрый способ проверить, является ли объект массивом или нет.
var arr = [];
arr.constructor.name ==='Array' //return true;
или
arr.constructor ===Array //return true;
или вы можете сделать служебную функцию:
function isArray(obj){ return obj && obj.constructor ===Array}
использование:
isArray(arr); //return true
function isArray(value) {
if (value) {
if (typeof value === 'object') {
return (Object.prototype.toString.call(value) == '[object Array]')
}
}
return false;
}
var ar = ["ff","tt"]
alert(isArray(ar))
Можно использовать следующее, если вы знаете, что у вашего объекта нет метода concat.
var arr = [];
if (typeof arr.concat === 'function') {
console.log("It an array");
}
Простая функция для проверки, является ли входное значение массивом следующим:
function isArray(value)
{
return Object.prototype.toString.call(value) === '[object Array]';
}
Это работает как кросс-браузер, так и старые браузеры. Это извлечено из T.J. Сообщение блога Броунов
Если только два типа значений, которые могут быть переданы этой функции, являются строкой или массивом строк, сохраняйте ее просто и используйте проверку typeof
для возможности строки:
function someFunc(arg) {
var arr = (typeof arg == "string") ? [arg] : arg;
}
Эта функция превратит почти что-нибудь в массив:
function arr(x) {
if(x === null || x === undefined) {
return [];
}
if(Array.isArray(x)) {
return x;
}
if(isString(x) || isNumber(x)) {
return [x];
}
if(x[Symbol.iterator] !== undefined || x.length !== undefined) {
return Array.from(x);
}
return [x];
}
function isString(x) {
return Object.prototype.toString.call(x) === "[object String]"
}
function isNumber(x) {
return Object.prototype.toString.call(x) === "[object Number]"
}
Он использует некоторые новые функции браузера, поэтому вы можете захотеть polyfill для максимальной поддержки.
Примеры:
> arr(null);
[]
> arr(undefined)
[]
> arr(3.14)
[ 3.14 ]
> arr(1/0)
[ Infinity ]
> gen = function*() { yield 1; yield 2; yield 3; }
[Function: gen]
> arr(gen())
[ 1, 2, 3 ]
> arr([4,5,6])
[ 4, 5, 6 ]
> arr("foo")
[ 'foo' ]
N.B. строки будут преобразованы в массив с одним элементом, а не с массивом символов. Удалите проверку isString
, если вы предпочтете ее наоборот.
Я использовал Array.isArray
здесь, потому что наиболее надежный, а также самый простой.
К счастью, ECMA 5 представила Array.isArray()
еще в декабре 2009 года. Если по какой-то причине вы используете версию JavaScript старше ECMA 5, обновите ее.
Однако, если вы настаиваете на этом, массивы имеют определенные свойства, которые отличает их от любого другого типа. Свойства, которые я не видел в других ответах. Давайте перейдем к политике JavaScript.
Массив - это объект (typeof [] === "object"
), но в отличие от традиционных объектов они имеют свойство length (typeof ( {}).length === "undefined"
). null
также является объектом (typeof null === "object"
), но вы не можете получить доступ к свойству null
поскольку null
не является объектом. Это ошибка в спецификации, которая полностью возвращается к самому началу JavaScript, когда объекты имеют тег типа 0
а null
был представлен как буквальный нулевой указатель 0x00
, что заставляло интерпретатор путать его с объектами.
К сожалению, это не учитывает []
vs {length:0}
. Поэтому мы должны перейти к цепочке прототипов.
( []).__proto__ === Array.prototype && ( []).__proto__ !== Object.prototype
.
Таким образом, без Array.isArray()
, это примерно то самое ближайшее, что мы можем получить:
function is_array(array){
return array !== null
&& typeof array === "object"
&& array.__proto__ === Array.prototype;
}
[ [], [1,2,3], {length: 0}, {},
1, 0, Infinity, NaN, "1", "[1,2,3]",
null, undefined, [null], [undefined], {a:[]},
[{}], [{length: 0}], [Infinity], [NaN],
{__proto__: Array.prototype}
].filter(is_array)
// Expected: [ [], [1,2,3], [null], [undefined], [{}], [{length: 0}], [Infinity], [NaN] ]
// Actual: [ [], [1,2,3], [null], [undefined], [{}], [{length: 0}], [Infinity], [NaN], {__proto__: Array.prototype} ]
Объект, злонамеренно предназначенный для того, чтобы выглядеть так же, как массив, фактически проходит тест turing. Однако заменить цепочку прототипов цепочкой прототипов Array достаточно, чтобы заставить ее действовать точно так же, как массив, эффективно создавая массив. Единственная вещь в мире, которая может Array.isArray()
такой объект, на самом деле не является массивом, это Array.isArray()
. Но для целей, которые вы обычно проверяете, является ли объект массивом, этот объект должен хорошо сочетаться с вашим кодом. Даже поведение, когда вы изменяете длину массива искусственно, одинаково: если длина больше, чем количество элементов в массиве, у вас будут "пустые слоты" этого специального "неявного неопределенного" типа, который как-то отличается от undefined, а также === undefined
; тот же тип, который является причиной того, что мы используем typeof obj !== "undefined"
чтобы избежать метаданных ReferenceError
поскольку obj === undefined
только не выдает ошибку, если obj
явно определен как undefined
.
a = {__proto__: Array.prototype}; // Array {}
a.push(5)
a // [5]
a.length = 5
a // [5, empty x 4]
b = a.map(n => n*n) // [25, empty x 4]
b.push(undefined)
b.push(undefined)
b // [25, empty x 4, undefined, undefined]
b[1] // undefined
b[1] === b[5] // true
Array.isArray(a) // false
Array.isArray(b) // true
Однако не используйте is_array()
. Одно дело - изобретать колесо для обучения. Это еще одна вещь, чтобы сделать это в производственном коде. Даже не используйте его как полипол. Поддержка старых версий JS означает поддержку старых браузеров, что означает поощрение использования небезопасного программного обеспечения, что позволяет подвергнуть пользователя опасности для вредоносного ПО.
A = [1,2,3]
console.log(A.map==[].map)
В поисках кратчайшей версии вот что я получил до сих пор.
Обратите внимание, что нет идеальной функции, которая всегда будет обнаруживать все возможные комбинации. Лучше знать все возможности и ограничения ваших инструментов, чем ожидать волшебный инструмент.
- 1
- 2
Другие вопросы по меткам javascript arrays javascript-objects или Задайте вопрос