我正在尝试编写一个函数,它要么接受字符串列表,要么接受单个字符串。如果它是一个字符串,那么我想把它转换成一个只有一个项的数组,这样我就可以在上面循环,而不用担心出错。
那么如何检查变量是否为数组?
我正在尝试编写一个函数,它要么接受字符串列表,要么接受单个字符串。如果它是一个字符串,那么我想把它转换成一个只有一个项的数组,这样我就可以在上面循环,而不用担心出错。
那么如何检查变量是否为数组?
当前回答
幸运的是,ECMAScript 5在2009年12月引入了Array.isArray()。如果出于某种原因,您使用的JavaScript版本早于ECMAScript 5,请升级。
但是,如果您坚持使用它,那么数组确实具有某些财产,可以将它们与任何其他类型区分开来。我在其他任何答案中都没有提到过的财产。让我们进入一些JavaScript政治。
数组是一个对象(typeof[]==“object”),但与传统对象不同,它们具有长度属性(typeof({}).length==“undefined”)。null也是一个对象(typeof null==“object”),但不能访问null属性,因为null不是对象。
这是规范中的一个bug,可以追溯到JavaScript的最开始,当时对象的类型标记为0,null表示为文本null指针0x00,这导致解释器将其与对象混淆。
不幸的是,这不能解释[]与{length:0}之间的关系。所以我们现在必须转向原型链。
( [] ).__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} ]
被恶意设计成看起来像数组的对象实际上通过了图灵测试。然而,用Array原型链替换原型链就足以使其像数组一样,有效地使其成为数组。
世界上唯一能告诉这样的对象实际上不是数组的是array.isArray()。但出于通常检查对象是否是数组的目的,所述对象应该在代码中表现良好。
甚至当你人为地改变数组长度时的行为也是一样的:如果长度比数组中的元素数长,你会有一个特殊的“隐式未定义”类型的“空槽”,这种类型在某种程度上不同于未定义,同时也是==未定义的;这就是我们使用typeof obj的原因!==“undefined”以避免引发ReferenceError,因为obj==undefineed仅在obj被显式定义为undefine时才会引发错误。
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()。为了学习目的重新发明轮子是一回事。在生产代码中这样做是另一回事。甚至不要将其用作polyfill。支持旧JavaScript版本意味着支持旧浏览器意味着鼓励使用不安全的软件意味着用户面临恶意软件的风险。
其他回答
这是所有方法中速度最快的(所有浏览器都支持):
function isArray(obj){
return !!obj && obj.constructor === Array;
}
检查其原型和Array.isArray之间存在差异:
function isArray(obj){
return Object.getPrototypeOf(obj) === Array.prototype
}
此函数将直接检查obj是否为数组。
但对于此代理对象:
var arr = [1,2,3]
var proxy = new Proxy(arr,{})
console.log(Array.isArray(proxy)) // true
Array.isArray将其作为Array。
因为我不喜欢任何Object.prototype调用,所以我寻找了另一种解决方案。特别是因为ChaosPandion的解决方案并不总是有效的,并且MidnightTortoise的isArray()解决方案不适用于来自DOM的数组(如getElementsByTagName)。最后,我找到了一个简单的跨浏览器解决方案,这可能也适用于Netscape 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");
这适用于所有情况吗?或者我的解决方案不起作用?
检查对象是否为数组的最简单快捷的方法。
var arr = [];
arr.constructor.name === 'Array' // Returns true;
or
arr.constructor === Array // Returns true;
或者您可以创建一个实用函数:
const isArray = (obj) => !!obj && obj.constructor === Array;
用法:
isArray(arr); // Returns true
您可以使用isArray方法,但我更愿意检查:
Object.getPrototypeOf(yourvariable)==Array.prototype