Я хотел бы проверить, является ли переменная либо массивом, либо единственным значением в JavaScript.
Я нашел возможное решение...
if (variable.constructor == Array)...
Это лучший способ сделать это?
Существует несколько способов проверки, является ли переменная массивом или нет. Лучшее решение - это тот, который вы выбрали.
variable.constructor === Array
Это самый быстрый метод в Chrome, и, скорее всего, все остальные браузеры. Все массивы - это объекты, поэтому проверка свойства constructor - быстрый процесс для движков JavaScript.
Если у вас возникли проблемы с выяснением, является ли свойство объектов массивом, вы должны сначала проверить, есть ли там свойство.
variable.prop && variable.prop.constructor === Array
Некоторые другие способы:
variable instanceof Array
Этот метод работает в 1/3 скорости в качестве первого примера. Все еще довольно солидно, выглядит чище, если вы все о хорошем коде и не столько о производительности. Обратите внимание, что проверка чисел не работает, так как variable instanceof Number
всегда возвращает false
. Обновление: instanceof
теперь идет 2/3 скорости!
Array.isArray(variable)
Этот последний, на мой взгляд, самый уродливый, и он один из самых медленных. В качестве первого примера используется скорость около 1/5. Array.prototype, на самом деле является массивом. вы можете прочитать об этом здесь https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/isArray
Итак, еще одно обновление
Object.prototype.toString.call(variable) === '[object Array]';
Этот парень самый медленный, пытаясь проверить массив. Тем не менее, это универсальный магазин для любого типа, который вы ищете. Однако, поскольку вы ищете массив, используйте самый быстрый метод выше.
Кроме того, я проверил некоторый тест: http://jsperf.com/instanceof-array-vs-array-isarray/33 Так что имейте немного удовольствия и проверьте его.
Примечание. @EscapeNetscape создал еще один тест, так как jsperf.com не работает. http://jsben.ch/#/QgYAV Я хотел убедиться, что исходная ссылка останется, когда jsperf возвращается в сеть.
Вы также можете использовать:
if (value instanceof Array) {
alert('value is Array!');
} else {
alert('Not an array');
}
Мне кажется, это довольно элегантное решение, но для каждого из них.
Изменить:
В ES5 теперь также есть:
Array.isArray(value);
Но это сломается на старых браузерах, если вы не используете полисы (в основном... IE8 или аналогичные).
Array instanceof Object == true
.
Я заметил, что кто-то упомянул jQuery, но я не знал, что существует функция isArray()
. Оказывается, он был добавлен в версию 1.3.
jQuery реализует его, как предлагает Питер:
isArray: function( obj ) {
return toString.call(obj) === "[object Array]";
},
Положив много веры в jQuery (особенно их методы совместимости с несколькими браузерами), я либо обновляюсь до версии 1.3, либо воспользуюсь их функцией (при условии, что обновление не вызовет слишком много проблем) или используйте этот предложенный метод непосредственно в мой код.
Большое спасибо за предложения.
Существует множество решений со всеми их собственными причудами. Эта страница дает хороший обзор. Одно из возможных решений:
function isArray(o) {
return Object.prototype.toString.call(o) === '[object Array]';
}
В современных браузерах (и некоторых устаревших браузерах) вы можете сделать
Array.isArray(obj)
(Поддерживается Chrome 5, Firefox 4.0, IE 9, Opera 10.5 и Safari 5)
Если вам необходимо поддерживать старые версии IE, вы можете использовать ES5-подкладку к polyfill Array.isArray; или добавьте следующее
# 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
Примечание: ключевое слово arguments
которое можно использовать для доступа к аргументу функции, не является массивом, хотя оно (как правило) ведет себя как единое целое:
var func = function() {
console.log(arguments) // [1, 2, 3]
console.log(arguments.length) // 3
console.log(Array.isArray(arguments)) // false !!!
console.log(arguments.slice) // undefined (Array.prototype methods not available)
console.log([3,4,5].slice) // function slice() { [native code] }
}
func(1, 2, 3)
prototype
? Кажется, это должен быть Object.prototype.toString.call
.
Это старый вопрос, но с той же проблемой я нашел очень элегантное решение, которое хочу поделиться.
Добавление прототипа в массив делает его очень простым
Array.prototype.isArray = true;
Теперь, если у вас есть объект, который вы хотите протестировать, чтобы проверить, нужен ли ему массив, который вам нужен, чтобы проверить новое свойство
var box = doSomething();
if (box.isArray) {
// do something
}
isArray доступен только в том случае, если его массив
Через Crockford:
function typeOf(value) {
var s = typeof value;
if (s === 'object') {
if (value) {
if (value instanceof Array) {
s = 'array';
}
} else {
s = 'null';
}
}
return s;
}
Основным недостатком упоминаний Крокфорда является невозможность правильно определить массивы, созданные в другом контексте, например, window
.
Эта страница имеет гораздо более сложную версию, если этого недостаточно.
Мне лично нравится предложение Питера: https://stackoverflow.com/questions/767486/how-do-you-check-if-a-variable-is-an-array-in-javascript (для ECMAScript 3. Для ECMAScript 5 используйте Array.isArray()
)
Комментарии к сообщению указывают, однако, что если toString()
вообще изменено, этот способ проверки массива завершится с ошибкой. Если вы действительно хотите быть конкретным и убедитесь, что toString()
не был изменен, и нет никаких проблем с атрибутом класса объектов ([object Array]
- это атрибут класса для объекта, который является массивом), то я рекомендую сделать что-то например:
//see if toString returns proper class attributes of objects that are arrays
//returns -1 if it fails test
//returns true if it passes test and it an array
//returns false if it passes test and it not an array
function is_array(o)
{
// make sure an array has a class attribute of [object Array]
var check_class = Object.prototype.toString.call([]);
if(check_class === '[object Array]')
{
// test passed, now check
return Object.prototype.toString.call(o) === '[object Array]';
}
else
{
// may want to change return value to something more desirable
return -1;
}
}
Обратите внимание, что в JavaScript. Окончательное руководство. 6-е издание, 7.10, говорит, что Array.isArray()
реализуется с использованием Object.prototype.toString.call()
в ECMAScript 5. Также обратите внимание, что если вы собираетесь беспокоиться о смене реализации toString()
, вам также следует беспокойство о каждом другом встроенном методе тоже. Зачем использовать push()
? Кто-то может это изменить! Такой подход глуп. Вышеупомянутая проверка является предлагаемым решением для тех, кто обеспокоен изменением toString()
, но я считаю, что проверка не нужна.
return Object.prototype.toString.call(o) === Object.prototype.toString.call([]);
Когда я разместил этот вопрос, версия JQuery, которую я использовал, не включала функцию isArray
. Если бы у меня было это, я бы, вероятно, просто использовал его, полагая, что реализация будет лучшим браузером, независимым способом выполнения этой конкретной проверки типа.
Так как JQuery теперь предлагает эту функцию, я всегда буду использовать ее...
$.isArray(obj);
(начиная с версии 1.6.2) Он по-прежнему реализуется с использованием сравнений строк в форме
toString.call(obj) === "[object Array]"
Если вы имеете дело только с EcmaScript 5 и выше, тогда вы можете использовать встроенную функцию Array.isArray
например,
Array.isArray([]) // true
Array.isArray("foo") // false
Array.isArray({}) // false
Думаю, я добавлю еще один вариант для тех, кто уже может использовать библиотеку Underscore.js в своем script. Underscore.js имеет функцию isArray() (см. http://underscorejs.org/#isArray).
_.isArray(object)
Возвращает true, если объект является массивом.
Array.isArray
подчеркивания использует собственный Array.isArray
если он доступен, в противном случае он использует метод toString
.
Если вы используете Angular, вы можете использовать функцию angular.isArray()
var myArray = [];
angular.isArray(myArray); // returns true
var myObj = {};
angular.isArray(myObj); //returns false
В Crockford JavaScript Хорошие части существует функция проверки, является ли данный аргумент массивом:
var is_array = function (value) {
return value &&
typeof value === 'object' &&
typeof value.length === 'number' &&
typeof value.splice === 'function' &&
!(value.propertyIsEnumerable('length'));
};
Он объясняет:
Сначала мы спрашиваем, правно ли это значение. Мы делаем это, чтобы отклонить нулевые и другие значения фальши. Во-вторых, мы спрашиваем, является ли typeof значением "object". Это будет верно для объектов, массивов и (странно) null. В-третьих, мы спрашиваем, имеет ли значение свойство length, которое является числом. Это всегда будет верно для массивов, но обычно это не для объектов. В-четвертых, мы спрашиваем, содержит ли значение метод сращивания. Это снова будет верно для всех массивов. Наконец, мы спрашиваем, является ли свойство length перечислимым (длина будет создаваться с помощью цикла for for?). Это будет ложно для всех массивов. Это самый надежный тест на массивность, который я нашел. К сожалению, это так сложно.
Универсальное решение ниже:
Object.prototype.toString.call(obj)=='[object Array]'
Начиная с ECMAScript 5, формальное решение:
Array.isArray(arr)
Кроме того, для старых библиотек JavaScript вы можете найти решение ниже, хотя оно недостаточно точное:
var is_array = function (value) {
return value &&
typeof value === 'object' &&
typeof value.length === 'number' &&
typeof value.splice === 'function' &&
!(value.propertyIsEnumerable('length'));
};
Решения от http://www.pixelstech.net/topic/85-How-to-check-whether-an-object-is-an-array-or-not-in-JavaScript
Я использовал эту строку кода:
if (variable.push) {
// variable is array, since AMAIK only arrays have push() method.
}
push
свойства будет считаться массивом.
упомянутый https://github.com/miksago/Evan.js/blob/master/src/evan.js
var isArray = Array.isArray || function(obj) {
return !!(obj && obj.concat && obj.unshift && !obj.callee);};
concat
и unshift
, не хватило бы , чтобы проверить на unshift
?
concat
или unshift
, но менее вероятно , чтобы иметь и другие.
Из w3schools:
function isArray(myArray) {
return myArray.constructor.toString().indexOf("Array") > -1;
}
Для тех, кто кодирует гольф, ненадежный тест с наименьшим количеством символов:
function isArray(a) {
return a.map;
}
Это обычно используется при перемещении/выравнивании иерархии:
function golf(a) {
return a.map?[].concat.apply([],a.map(golf)):a;
}
input: [1,2,[3,4,[5],6],[7,[8,[9]]]]
output: [1, 2, 3, 4, 5, 6, 7, 8, 9]
Я думаю, используя myObj.constructor == Object и myArray.constructor == Массив - лучший способ. Его почти в 20 раз быстрее, чем использование toString(). Если вы расширяете объекты своими собственными конструкторами и хотите, чтобы эти творения считались "объектами", а это не работает, но в противном случае его путь быстрее. typeof так же быстро, как и метод конструктора, но typeof [] == 'object' возвращает true, что часто будет нежелательным. http://jsperf.com/constructor-vs-tostring
Следует отметить, что null.constructor выдает ошибку, поэтому, если вы можете проверить нулевые значения, вам нужно будет сначала сделать, если (testThing! == null) {}
Я создал этот немного кода, который может возвращать истинные типы.
Я пока не уверен в производительности, но это попытка правильно идентифицировать typeof.
https://github.com/valtido/better-typeOf также немного побеседовал об этом здесь http://www.jqui.net/jquery/better-typeof-than-the-javascript-native-typeof/
он работает, подобно текущему типу.
var user = [1,2,3]
typeOf(user); //[object Array]
Он думает, что может потребоваться немного тонкой настройки, и принять во внимание вещи, я не сталкивался или не тестировал их должным образом. поэтому приветствуются дальнейшие улучшения, независимо от того, насколько они эффективны по производительности или неправильно переупорядочивают typeOf.
Мне понравился ответ Брайана:
function is_array(o){
// make sure an array has a class attribute of [object Array]
var check_class = Object.prototype.toString.call([]);
if(check_class === '[object Array]') {
// test passed, now check
return Object.prototype.toString.call(o) === '[object Array]';
} else{
// may want to change return value to something more desirable
return -1;
}
}
но вы можете просто сделать следующее:
return Object.prototype.toString.call(o) === Object.prototype.toString.call([]);
function isArray(x){
return ((x != null) && (typeof x.push != "undefined"));
}
Так как свойство .length является специальным для массивов в javascript, вы можете просто сказать
obj.length === +obj.length // true if obj is an array
Underscorejs и несколько других библиотек используют этот короткий и простой трюк.
Что-то, с чем я только что придумал:
if (item.length)
//This is an array
else
//not an array