关于javascript:如何检查对象是否是数组?

How to check if an object is an array?

我正在尝试编写一个函数,它要么接受一个字符串列表,要么只接受一个字符串。如果它是一个字符串,那么我想将它转换为仅包含一个项的数组。然后我就可以循环使用它,而不用担心出错。

那么,如何检查变量是否是一个数组呢?

我总结了下面的各种解决方案,并创建了一个JSPerf测试。


ecmascript标准中给出的查找对象类的方法是使用Object.prototype中的toString方法。

1
2
3
if( Object.prototype.toString.call( someVar ) === '[object Array]' ) {
    alert( 'Array!' );
}

或者您可以使用typeof来测试它是否是字符串:

1
2
3
if( typeof someVar === 'string' ) {
    someVar = [ someVar ];
}

或者,如果您不关心性能,可以对新的空数组执行concat

1
someVar = [].concat( someVar );

还可以直接查询构造函数:

1
2
3
if (somevar.constructor.name =="Array") {
    // do something
}

从@T.J.Crowder的博客中,可以看到一个彻底的治疗方法,如下面他的评论所示。

查看此基准以了解哪个方法执行得更好:http://jsben.ch//qgyav

从@bharath使用es6将字符串转换为数组以回答以下问题:

1
2
3
const convertStringToArray = (object) => {
   return (typeof object === 'string') ? Array(object) : object
}

假设:

1
2
3
4
5
6
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

1
2
if (Array.isArray)
    return Array.isArray(v);

您也可以尝试使用instanceof运算符

1
v instanceof Array


在现代浏览器中,您可以

1
Array.isArray(obj)

(支持Chrome5、Firefox 4.0、IE 9、Opera10.5和Safari 5)

为了向后兼容,可以添加以下内容

1
2
3
4
5
6
# 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

1
obj instanceof Array


jquery还提供了$.isArray()方法:

1
2
3
4
5
6
7
var a = ["A","AA","AAA"];

if($.isArray(a)) {
  alert("a is an array!");
} else {
  alert("a is not an array!");
}
1
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js">


这是所有方法中最快的(支持所有浏览器):

1
2
3
function isArray(obj){
    return !!obj && obj.constructor === Array;
}


假设下面有这个数组:

1
var arr = [1,2,3,4,5];

javascript(新浏览器和旧浏览器):

1
2
3
function isArray(arr) {
  return arr.constructor.toString().indexOf("Array") > -1;
}

1
2
3
function isArray(arr) {
  return arr instanceof Array;
}

1
2
3
function isArray(arr) {
  return Object.prototype.toString.call(arr) === '[object Array]';
}

然后这样称呼它:

1
isArray(arr);

javascript(ie9+、ch5+、ff4+、saf5+、operat10.5+)

1
Array.isArray(arr);

jQuery:

1
$.isArray(arr);

Angular:

1
angular.isArray(arr);

下划线和阴影:

1
_.isArray(arr);

array.isarray工作速度很快,但并非所有版本的浏览器都支持它。因此,您可以为其他人例外并使用通用方法:

1
2
3
4
5
6
    Utils = {};    
    Utils.isArray = ('isArray' in Array) ?
        Array.isArray :
        function (value) {
            return Object.prototype.toString.call(value) === '[object Array]';
        }


检查此项的简单功能:

1
2
3
4
5
function isArray(object)
{
    if (object.constructor === Array) return true;
    else return false;
}


这个问题只有一条解决方案

1
x instanceof Array

其中x是变量,如果x是数组,则返回true,否则返回false。


正如MDN在这里所说:

use Array.isArray or Object.prototype.toString.call to differentiate
regular objects from arrays

这样地:

  • Object.prototype.toString.call(arr) === '[object Array]'

  • Array.isArray(arr)


您可以检查变量的类型是否为数组;

1
2
3
4
5
6
var myArray=[];

if(myArray instanceof Array)
{
....
}


我会做一个函数来测试你正在处理的对象的类型…

1
2
3
4
5
6
7
8
9
10
11
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语句…

1
2
3
4
5
if(whatAmI(myVar) ==="Array"){
    // do array stuff
} else { // could also check `if(whatAmI(myVar) ==="String")` here to be sure
    // do string stuff
}

考虑到以下评论,我试图改进此答案:

1
var isArray = myArray && myArray.constructor === Array;

它除去if/else,并说明数组可能为空或未定义


我用一种非常简单的方法来做这件事。为我工作。有什么缺点吗?

1
2
3
4
5
Array.prototype.isArray = true;

a=[]; b={};
a.isArray  // true
b.isArray  // (undefined -> false)


I have updated the jsperf fiddle with two alternative methods as well as error checking.

It turns out that the method defining a constant value in the 'Object' and 'Array' prototypes is faster than any of the other methods. It is a somewhat surprising result.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/* 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/>");

如果变量接受未定义的值,这两个方法不起作用,但是如果您确定它们具有值,那么它们就起作用。关于检查一个值是数组还是单个值,考虑到性能,第二个方法看起来像一个有效的快速方法。它比Chrome上的"instanceof"稍快,比Internet Explorer、Opera和Safari(在我的机器上)中的第二最佳方法快两倍。


https://developer.mozilla.org/en-us/docs/javascript/reference/global_objects/array/isarray

1
2
3
Array.isArray = Array.isArray || function (vArg) {
    return Object.prototype.toString.call(vArg) ==="[object Array]";
};

我知道,人们正在寻找某种原始的javascript方法。但是如果你想少想一想,可以看看这里:http://underlinejs.org/isarray

1
_.isArray(object)

如果对象是数组,则返回true。

1
2
3
4
(function(){ return _.isArray(arguments); })();
=> false
_.isArray([1,2,3]);
=> true


以下是我的懒惰方法:

1
2
3
4
5
6
7
8
9
10
11
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边界工作,但对于我的用例来说,这不是问题。


StoyanStefanov的书javascript模式中有一个很好的例子,它假定可以处理所有可能的问题,并使用ecmascript 5方法array.is array()。

所以这里是:

1
2
3
4
5
if (typeof Array.isArray ==="undefined") {
    Array.isArray = function (arg) {
        return Object.prototype.toString.call(arg) ==="[object Array]";
    };
}

顺便说一下,如果您使用jquery,您可以使用它的方法$.isarray()。


如果您知道您的对象没有concat方法,那么可以使用下面的内容。

1
2
3
4
var arr = [];
if (typeof arr.concat === 'function') {
    console.log("It's an array");
}


检查对象是否为数组的最简单和最快速的方法。

1
2
 var arr = [];
  arr.constructor.name ==='Array'  //return true;

1
arr.constructor ===Array //return true;

或者您可以使实用程序功能:

1
function isArray(obj){ return obj && obj.constructor ===Array}

用途:

1
isArray(arr); //return true

你可以用Isarray方法,但我想查一下

Object.getPrototypeOf(yourvariable) === Array.prototype


我见过的最好的解决方案是用跨浏览器替换typeof。在这里检查安格斯·克罗尔的解决方案。

下面是tl;dr版本,但是这篇文章是关于这个问题的一个很好的讨论,因此如果您有时间的话,您应该阅读它。

1
2
3
4
5
6
7
8
9
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 */};

此函数将几乎所有内容转换为数组:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
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]"
}

它使用了一些更新的浏览器功能,因此您可能需要多道填充以获得最大支持。

实例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
> 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' ]

注意,字符串将被转换为一个带有单个元素的数组,而不是一个字符数组。删除EDOCX1[4]复选框,如果您希望使用相反的方式。

我在这里使用了Array.isArray,因为它是最健壮的,也是最简单的。


在您的例子中,您可以使用数组的concat方法,它可以接受单个对象,也可以接受数组(甚至组合起来):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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似乎是最古老的数组方法之一(即使是IE5.5也很熟悉)。


用于测试输入值是否为数组的简单函数如下:

1
2
3
4
function isArray(value)
{
  return Object.prototype.toString.call(value) === '[object Array]';
}

这适用于跨浏览器和旧浏览器。这是从T.J.Crowders的博客中提取的。


1
2
3
4
5
6
7
8
9
10
11
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))

1
2
A = [1,2,3]
console.log(A.map==[].map)

为了寻找最短的版本,这里是我到目前为止得到的。

注意,没有一个完美的功能可以始终检测所有可能的组合。了解你的工具的所有能力和局限性比期待一个神奇的工具要好。


如果可以传递给此函数的值只有两种,一种是字符串或字符串数组,请保持简单,并使用typeof检查字符串的可能性:

1
2
3
function someFunc(arg) {
    var arr = (typeof arg =="string") ? [arg] : arg;
}


您可以尝试以下操作:

1
2
3
4
5
6
var arr = []; (or) arr = new Array();
var obj = {}; (or) arr = new Object();

arr.constructor.prototype.hasOwnProperty('push') //true

obj.constructor.prototype.hasOwnProperty('push') // false


值得庆幸的是,ECMA 5早在2009年12月就推出了Array.isArray()。如果出于某种原因,您使用的是早于ECMA 5的javascript版本,请升级。

但是,如果您坚持这样做,那么数组确实具有某些属性,可以将它们与任何其他类型区分开来。我在其他答案中没有提到的属性。让我们进入一些JavaScript政治。

数组是一个对象(typeof [] ==="object"),但与传统对象不同,它们具有长度属性(typeof ( {} ).length ==="undefined")。null也是一个对象(typeof null ==="object"),但是你不能访问null的属性,因为null不是一个对象。这是规范中的一个bug,它可以一直追溯到JavaScript的最开始,当时对象的类型标记为0null表示为文本空指针0x00,这导致解释器将其与对象混淆。

不幸的是,这并不能解释[]{length:0}之间的关系。所以我们现在必须转向原型链。

( [] ).__proto__ === Array.prototype && ( [] ).__proto__ !== Object.prototype

因此,如果没有Array.isArray(),这几乎是我们能得到的最接近的:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
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} ]

被恶意设计成看起来像数组的对象实际上通过了图灵测试。然而,将原型链替换为数组原型链就足以使其像数组一样工作,有效地使其成为数组。世界上唯一能分辨出这样一个物体的东西实际上不是一个数组,是Array.isArray()。但是为了达到这个目的,您通常会检查一个对象是否是一个数组,所说的对象应该能很好地处理您的代码。即使是人为改变数组长度时的行为也是一样的:如果长度大于数组中元素的数量,则会有一个特殊的"隐式未定义"类型的"空槽",它在某种程度上不同于未定义的类型,同时也是=== undefined;这也是我们使用typeof obj !=="undefined"的原因。]避免抛出ReferenceError,因为obj === undefined只在obj明确定义为undefined时才抛出错误。

1
2
3
4
5
6
7
8
9
10
11
12
13
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版本意味着支持旧的浏览器意味着鼓励使用不安全的软件意味着让用户面临恶意软件的风险。


1
2
3
4
5
6
7
var is_array = function (value) {
   return value &&
     typeof value === 'object' &&
     typeof value.length === 'number' &&
     typeof value.splice === 'function' &&
    !(value.propertyIsEnumerable('length'));
};

此功能摘自《JS好零件》一书,非常适合我。


最佳实践是使用constructor比较它,类似这样

1
2
3
if(some_variable.constructor === Array){
  // do something
}

您也可以使用其他方法,如typeOf,将其转换为字符串,然后进行比较,但将其与数据类型进行比较始终是一种更好的方法。


其他方法也可以检查,但我更喜欢以下方法尽我所能检查(因为你可以很容易地检查其他对象的类型)。

1
2
3
4
5
6
7
8
> a = [1, 2]
[ 1, 2 ]
>
> Object.prototype.toString.call(a).slice(8,).replace(/\]$/, '')
'Array'
>
> Object.prototype.toString.call([]).slice(8,-1) // best approach
'Array'

说明(在node repl上有简单的示例)»;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
> 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]'
>

对象或阵列

1
2
3
4
5
6
> Object.prototype.toString.call(o).slice(8,).replace(/\]$/, '')
'Object'
>
> Object.prototype.toString.call(a).slice(8,).replace(/\]$/, '')
'Array'
>

空或未定义»;

1
2
3
4
5
> Object.prototype.toString.call(undefined).slice(8,).replace(/\]$/, '')
'Undefined'
> Object.prototype.toString.call(null).slice(8,).replace(/\]$/, '')
'Null'
>

弦乐;

1
2
> Object.prototype.toString.call('ok').slice(8,).replace(/\]$/, '')
'String'

数量和数量;

1
2
3
4
5
6
7
> 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代替正则表达式,如下所示。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
> 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'
>


因为我不喜欢任何object.prototype调用,所以我搜索了另一个解决方案。尤其是因为超空间的解决方案并不总是有效,而且使用isArray()的中夜龟解决方案不适用于来自DOM的数组(如GetElementsByTagname)。最后,我找到了一个简单的跨浏览器解决方案,它可能也可以与Netscape 4一起使用。;)

只是这4行(检查任何对象h):

1
2
3
4
5
6
function isArray(h){
    if((h.length!=undefined&&h[0]!=undefined)||(h.length===0&&h[0]===undefined)){
        return true;
    }
    else{ return false; }
}

我已经测试了这些数组(都返回true):

1
2
3
4
5
6
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");

有人能证实这对所有情况都有效吗?还是有人发现我的解决方案不起作用?


可以使用此函数获取数据类型。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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')};


您可以在push中找到,如下所示:

1
2
3
4
5
6
7
8
function isArray(obj){
   return (typeof obj.push=== 'function')?true:false;
}

var array=new Array();
or
var array=['a','b','c'];
console.log(isArray(array));


还可以检查数组的长度属性。当您试图访问数组的长度属性时,它将返回一个数字(空数组为0),而如果您试图访问对象的长度属性,它将返回未定义。

1
2
3
if(Object.prototype.toString.call(arrayList) === '[object Array]') {
  console.log('Array!');
}


签出它的原型和array.is array之间存在差异:

1
2
3
function isArray(obj){
    return Object.getPrototypeOf(obj) === Array.prototype
}

此函数将直接检查obj是否为数组

但是对于这个代理对象:

1
2
3
4
5
var arr = [1,2,3]

var proxy = new Proxy(arr,{})

console.log(Array.isArray(proxy)) // true

Array.isArray将把它作为数组。


下面是一段代码片段,它将解释在学习JS(与我不同)的早期阶段应该知道的数组的一个重要事实。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// 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.is array()方法确定output是一个数组。


我知道这是一个古老的问题,但这里有一个解决方案,我想出并一直用于我的项目…

1
2
3
4
5
6
7
8
9
10
function isArray (o) {
    return typeof o ==="object" && o.length !== undefined;
}

isArray({}); // false
isArray(1); // false
isArray("str"); // false
isArray(function(){}); // false

isArray([]); // true

唯一的陷阱是,如果对象恰好具有length属性,它将给出一个假正值:

1
isArray({length:0}); // true

如果您同意这个缺点,并且知道纯对象不会有这个属性,那么它是一个干净的解决方案,应该比object.prototype.toString.call方法更快。


我用的是:

1
2
3
4
5
function isArray(input) {
  if (input instanceof Array || Object.prototype.toString.call(input) === '[object Array]') {
        return true;
  } else return false;
}

[cc lang="javascript"] var length = 16; // Number
var lastName ="Johnson"; // String
var cars = ["Saab","Volvo","BMW"]; // Array
var x = {firstName:"John", lastName:"Doe