Я пытаюсь написать функцию, которая либо принимает список строк, либо одну строку. Если это строка, то я хочу преобразовать ее в массив только с одним элементом. Тогда я могу зациклиться на нем, не опасаясь ошибки.
Итак, как мне проверить, является ли переменная массивом?
Я рассмотрел различные решения ниже и создал тест jsperf.
В современных браузерах вы можете сделать
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
Array.isArray
if (typeof Array.isArray === 'undefined') {
можно изменить на if(!Array.isArray) {
Метод, указанный в стандарте 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']
toString
- один из способов пойти. Я делаю небольшую сводку здесь: blog.niftysnippets.org/2010/09/say-what.html
Я бы сначала проверил, поддерживает ли ваша реализация isArray
:
if (Array.isArray)
return Array.isArray(v);
Вы также можете попробовать использовать оператор instanceof
v instanceof Array
v instanceof Array
вернет false, если v
был создан в другом фрейме ( v
является экземпляром класса thatFrame.contentWindow.Array
).
Array.isArray
определен как часть ECMAScript 5 / Javascript 1.8.5.
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]';
}
.toString()
из Object.prototype
. Прямо сейчас вы используете window.toString()
, что не то же самое.
window.toString
делает то же самое, что Object.prototype.toString
только в Chrome.
Простая функция для проверки:
function isArray(object)
{
if (object.constructor === Array) return true;
else return false;
}
return object.constructor === Array
- но вы уверены, что это вернет true только для массивов?
if(x) 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 - если нет.
typeof
сравнения.
Поскольку MDN говорит здесь:
используйте Array.isArray или Object.prototype.toString.call, чтобы различать регулярные объекты из массивов
Вот так:
Object.prototype.toString.call(arr) === '[object Array]'
, или
Array.isArray(arr)
Вы можете проверить тип переменной, является ли она массивом:
var myArray=[];
if(myArray instanceof Array)
{
....
}
instanceof
. Я думаю, что это терпит неудачу в нескольких странных сценариях.
Я бы сделал функцию для проверки типа объекта, с которым вы имеете дело...
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
}
Я делаю это очень просто. Работает на меня. Любые недостатки?
Array.prototype.isArray = true;
a=[]; b={};
a.isArray // true
b.isArray // (undefined -> false)
{isArray:true}
JSON.parse(someDataFromElsewhere).items.isArray
может вернуть true (в зависимости от данных) и нарушить ваш код.
Это моя попытка улучшить этот ответ с учетом комментариев:
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
Object.getPrototypeOf(yourvariable)
возвращает прототип объекта Array. И код является самым быстрым и безопасным, чтобы на него можно было положиться.
В книге Стояна Стефанова есть хороший пример 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()
if(!Array.isArray) {...
?
Вот мой ленивый подход:
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
, но для моего это не проблема.
Лучшее решение, которое я видел, это кросс-браузерная замена для 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 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
здесь, потому что наиболее надежный, а также самый простой.
Можно использовать следующее, если вы знаете, что у вашего объекта нет метода 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. Сообщение блога Броунов
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))
Если только два типа значений, которые могут быть переданы этой функции, являются строкой или массивом строк, сохраняйте ее просто и используйте проверку typeof
для возможности строки:
function someFunc(arg) {
var arr = (typeof arg == "string") ? [arg] : arg;
}
К счастью, 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 означает поддержку старых браузеров, что означает поощрение использования небезопасного программного обеспечения, что позволяет подвергнуть пользователя опасности для вредоносного ПО.
В вашем случае вы можете использовать метод concat
Array, который может принимать как отдельные объекты, так и массив (и даже комбинированные ):
function myFunc(stringOrArray)
{
var arr = [].concat(stringOrArray);
console.log(arr);
arr.forEach(function(item, i)
{
console.log(i, "=", item);
})
}
myFunc("one string");
myFunc(["one string", "second", "third"]);
concat
кажется одним из старейших методов Array (даже IE 5.5 хорошо это знает).
Вы можете попробовать следующее:
var arr = []; (or) arr = new Array();
var obj = {}; (or) arr = new Object();
arr.constructor.prototype.hasOwnProperty('push') //true
obj.constructor.prototype.hasOwnProperty('push') // false
A = [1,2,3]
console.log(A.map==[].map)
В поисках кратчайшей версии вот что я получил до сих пор.
Обратите внимание, что нет идеальной функции, которая всегда будет обнаруживать все возможные комбинации. Лучше знать все возможности и ограничения ваших инструментов, чем ожидать волшебный инструмент.
A.map !== undefined
но да, это может быть скользкой дорогой в мире обезьяньих патчеров;)
Другие методы также существуют для проверки, но я предпочитаю следующий метод, как лучше всего проверить (поскольку вы можете легко проверить типы других объектов).
> a = [1, 2]
[ 1, 2 ]
>
> Object.prototype.toString.call(a).slice(8,).replace(/\]$/, '')
'Array'
>
> Object.prototype.toString.call([]).slice(8,-1) // best approach
'Array'
Объяснение (с простыми примерами на узле REPL) "
> o = {'ok': 1}
{ ok: 1 }
> a = [1, 2]
[ 1, 2 ]
> typeof o
'object'
> typeof a
'object'
>
> Object.prototype.toString.call(o)
'[object Object]'
> Object.prototype.toString.call(a)
'[object Array]'
>
Объект или массив "
> Object.prototype.toString.call(o).slice(8,).replace(/\]$/, '')
'Object'
>
> Object.prototype.toString.call(a).slice(8,).replace(/\]$/, '')
'Array'
>
Null или Undefined "
> Object.prototype.toString.call(undefined).slice(8,).replace(/\]$/, '')
'Undefined'
> Object.prototype.toString.call(null).slice(8,).replace(/\]$/, '')
'Null'
>
String "
> Object.prototype.toString.call('ok').slice(8,).replace(/\]$/, '')
'String'
Число "
> Object.prototype.toString.call(19).slice(8,).replace(/\]$/, '')
'Number'
> Object.prototype.toString.call(19.0).slice(8,).replace(/\]$/, '')
'Number'
> Object.prototype.toString.call(19.7).slice(8,).replace(/\]$/, '')
'Number'
>
Я ценю предложение @mpen
использовать -1 вместо регулярного выражения следующим образом.
> Object.prototype.toString.call(12).slice(8,-1)
'Number'
>
> Object.prototype.toString.call(12.0).slice(8,-1)
'Number'
>
> Object.prototype.toString.call([]).slice(8,-1)
'Array'
> Object.prototype.toString.call({}).slice(8,-1)
'Object'
>
> Object.prototype.toString.call('').slice(8,-1)
'String'
>
-1
как 2-й аргумент, чтобы slice
и сохранить регулярное выражение для дождливого дня.
@mpen
. Я добавил ваши предложения.
var is_array = function (value) {
return value &&
typeof value === 'object' &&
typeof value.length === 'number' &&
typeof value.splice === 'function' &&
!(value.propertyIsEnumerable('length'));
};
Эта функция взята из книги "JS good parts", отлично подходит для меня.
var object = {splice: function(){}}; Object.defineProperty(object, "length", {value: 1, enumerable: false}); console.log(is_array(object));
Вот фрагмент кода, который объяснит важный факт массивов, которые должны быть известны на ранних этапах изучения JS (в отличие от меня).
// this functions puts a string inside an array
var stringInsideArray = function(input) {
if (typeof input === 'string') {
return [input];
}
else if (Array.isArray(input)) {
return input;
}
else {
throw new Error("Input is not a string!");
}
}
var output = stringInsideArray('hello');
console.log('step one output: ', output); // ["hello"]
// use typeof method to verify output is an object
console.log('step two output: ', typeof output); // object
// use Array.isArray() method to verify output is an array
console.log('step three output: ', Array.isArray(output)); // true
Массивы, по сути, объекты.
Используя оператор typeof, вывод stringInsideArray('hello')
доказывает, что ["hello"]
действительно является объектом. Это сбило меня с толку дольше всего, потому что я предполагал, что массивы будут типом данных JavaScript...
Существует только 7 типов данных JS, и массивы НЕ являются одним из них.
Чтобы ответить на ваш вопрос, использование метода Array.isArray() определяет, что output
являются массивом.
[].concat(string)
- это довольно странный способ написания [string]
.
есть разница между checkout it prototype и Array.isArray:
function isArray(obj){
return Object.getPrototypeOf(obj) === Array.prototype
}
эта функция будет напрямую проверять, является ли объект массивом
но для этого объекта Proxy:
var arr = [1,2,3]
var proxy = new Proxy(arr,{})
console.log(Array.isArray(proxy)) // true
Array.isArray
примет его как массив.
isArray
не вернет true для Proxy, но это не так; они оба возвращают true
для Прокси (и непроксируемых массивов)
Вы также можете проверить свойство массива. Когда вы попытаетесь получить доступ к свойству length массива, он вернет число (0 для пустого массива), а если вы попытаетесь получить доступ к свойству length объекта, оно вернется не определено.
if(Object.prototype.toString.call(arrayList) === '[object Array]') {
console.log('Array!');
}
.length
.
Вот то, что я использую:
function isArray(input) {
if (input instanceof Array || Object.prototype.toString.call(input) === '[object Array]') {
return true;
} else return false;
}
Вы можете найти с помощью push
, как показано ниже:
function isArray(obj){
return (typeof obj.push=== 'function')?true:false;
}
var array=new Array();
or
var array=['a','b','c'];
console.log(isArray(array));
Вы можете использовать эту функцию для получения типа данных.
var myAr = [1,2];
checkType(myAr);
function checkType(data){
if(typeof data ==='object'){
if(Object.prototype.toString.call(data).indexOf('Array')!==(-1)){
return 'array';
} else{
return 'object';
}
} else {
return typeof data;
}
}
if(checkType(myAr) === 'array'){console.log('yes, It is an array')};
Я знаю, что это старый вопрос, но вот решение, которое я придумал и использовал для своих проектов...
function isArray (o) {
return typeof o === "object" && o.length !== undefined;
}
isArray({}); // false
isArray(1); // false
isArray("str"); // false
isArray(function(){}); // false
isArray([]); // true
Единственная ошибка заключается в том, что она даст ложный положительный результат, если ваш объект имеет свойство length:
isArray({length:0}); // true
Если вы в порядке с этим недостатком и знаете, что ваши чистые объекты не будут иметь это свойство, это чистое решение и должно быть быстрее, чем метод Object.prototype.toString.call.
Так как мне не нравятся вызовы Object.prototype, я искал другое решение. Тем более, что решения ChaosPandion не всегда будут работать, а решение MidnightTortoise с isArray()
не работает с массивами, поступающими из DOM (например, getElementsByTagName). И, наконец, я нашел простое и кросс-браузерное решение, которое, вероятно, также могло бы работать с Netscape 4.;)
Это только эти 4 строки (проверка любого объекта h
):
function isArray(h){
if((h.length!=undefined&&h[0]!=undefined)||(h.length===0&&h[0]===undefined)){
return true;
}
else{ return false; }
}
Я уже тестировал эти массивы (все возвращают true):
1) array=d.getElementsByName('some_element'); //'some_element' can be a real or unreal element
2) array=[];
3) array=[10];
4) array=new Array();
5) array=new Array();
array.push("whatever");
Кто-нибудь может подтвердить, что это работает для всех случаев? Или кто-нибудь найдет случай, когда мое решение не работает?
isArray(function(){}); // true
, isArray("foo"); // true
, isArray({length:0}); // true
var length = 16; // Number
var lastName = "Johnson"; // String
var cars = ["Saab", "Volvo", "BMW"]; // Array
var x = {firstName:"John", lastName:"Doe"};
Object.prototype.myCheck= function(){
if (this.constructor === Array){
alert('array');
}else if (this.constructor === Object)
{
alert('object');
}else if (this.constructor === Number)
{
alert('number');
}else if (this.constructor === String)
{
alert('string');
}
}
cars.myCheck();
lastName.myCheck();
length.myCheck();
cars.myCheck()
?
arr.constructor === Array
самый быстрый.