How to check if an object is an array?
我正在尝试编写一个函数,它要么接受一个字符串列表,要么只接受一个字符串。如果它是一个字符串,那么我想将它转换为仅包含一个项的数组。然后我就可以循环使用它,而不用担心出错。
那么,如何检查变量是否是一个数组呢?
我总结了下面的各种解决方案,并创建了一个JSPerf测试。
ecmascript标准中给出的查找对象类的方法是使用
1 2 3 | if( Object.prototype.toString.call( someVar ) === '[object Array]' ) { alert( 'Array!' ); } |
或者您可以使用
1 2 3 | if( typeof someVar === 'string' ) { someVar = [ someVar ]; } |
或者,如果您不关心性能,可以对新的空数组执行
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'] |
我首先检查一下您的实现是否支持
1 2 | if (Array.isArray) return Array.isArray(v); |
您也可以尝试使用
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,可以使用
如果不需要检测在不同帧中创建的数组,也可以使用
1 | obj instanceof Array |
jquery还提供了
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 |
我知道"破坏"原型是一种亵渎,但它的性能明显优于推荐的
注意:这种方法的一个缺陷是它不能跨
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方法,但我想查一下
我见过的最好的解决方案是用跨浏览器替换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]复选框,如果您希望使用相反的方式。
我在这里使用了
在您的例子中,您可以使用数组的
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"]); |
用于测试输入值是否为数组的简单函数如下:
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) |
为了寻找最短的版本,这里是我到目前为止得到的。
注意,没有一个完美的功能可以始终检测所有可能的组合。了解你的工具的所有能力和局限性比期待一个神奇的工具要好。
如果可以传递给此函数的值只有两种,一种是字符串或字符串数组,请保持简单,并使用
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月就推出了
但是,如果您坚持这样做,那么数组确实具有某些属性,可以将它们与任何其他类型区分开来。我在其他答案中没有提到的属性。让我们进入一些JavaScript政治。
数组是一个对象(
不幸的是,这并不能解释
因此,如果没有
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} ] |
被恶意设计成看起来像数组的对象实际上通过了图灵测试。然而,将原型链替换为数组原型链就足以使其像数组一样工作,有效地使其成为数组。世界上唯一能分辨出这样一个物体的东西实际上不是一个数组,是
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 |
不过,不要使用
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好零件》一书,非常适合我。
最佳实践是使用
1 2 3 | if(some_variable.constructor === Array){ // do something } |
您也可以使用其他方法,如
其他方法也可以检查,但我更喜欢以下方法尽我所能检查(因为你可以很容易地检查其他对象的类型)。
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' > |
感谢
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调用,所以我搜索了另一个解决方案。尤其是因为超空间的解决方案并不总是有效,而且使用
只是这4行(检查任何对象
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')}; |
您可以在
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 |
下面是一段代码片段,它将解释在学习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运算符,
只有7个JS数据类型,数组不是其中之一。
为了回答您的问题,使用array.is array()方法确定
我知道这是一个古老的问题,但这里有一个解决方案,我想出并一直用于我的项目…
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