判断是否是数组的⼏种办法
1.通过instanceof判断
instanceof运算符⽤于检验构造函数的prototype属性是否出现在对象的原型链中的任何位置,返回⼀个布尔值。
let a = [];
a instanceof Array; //true
let b = {};
b instanceof Array; //false
在上⽅代码中,instanceof运算符检测Array.prototype属性是否存在于变量a的原型链上,显然a是⼀个数组,拥有Array.prototype属性,所以为true。
存在问题:
需要注意的是,prototype属性是可以修改的,所以并不是最初判断为true就⼀定永远为真。
其次,当我们的脚本拥有多个全局环境,例如html中拥有多个iframe对象,instanceof的验证结果可能不会符合预期,例如:
//为body创建并添加⼀个iframe对象
var iframe = ateElement('iframe');
document.body.appendChild(iframe);
//取得iframe对象的构造数组⽅法
xArray = window.frames[0].Array;
//通过构造函数获取⼀个实例
var arr = new xArray(1,2,3);
arr instanceof Array;//false
导致这种问题是因为iframe会产⽣新的全局环境,它也会拥有⾃⼰的Array.prototype属性,让不同环境下的属性相同很明显是不安全的做法,所以Array.prototype !== window.frames[0].Array.prototype,想
要arr instanceof Array为true,你得保证arr是由原始Array构造函数创建时才可⾏。
2.通过constructor判断
我们知道,实例的构造函数属性constructor指向构造函数,那么通过constructor属性也可以判断是否为⼀个数组。
let a = [1,3,4];
同样,这种判断也会存在多个全局环境的问题,导致的问题与instanceof相同。
//为body创建并添加⼀个iframe标签
var iframe = ateElement('iframe');
document.body.appendChild(iframe);
//取得iframe对象的构造数组⽅法
xArray = window.frames[window.frames.length-1].Array;
//通过构造函数获取⼀个实例
var arr = new xArray(1,2,3);
3.通过String.call()判断
String().call()可以获取到对象的不同类型,例如
let a = [1,2,3]
String.call(a) === '[object Array]';//true
它强⼤的地⽅在于不仅仅可以检验是否为数组,⽐如是否是⼀个函数,是否是数字等等
//检验是否是函数
let a = function () {};
String.call(a) === '[object Function]';//true
/
/检验是否是数字
let b = 1;
String.call(a) === '[object Number]';//true
甚⾄对于多全局环境时, String().call()也能符合预期处理判断。
//为body创建并添加⼀个iframe标签
var iframe = ateElement('iframe');
document.body.appendChild(iframe);
//取得iframe对象的构造数组⽅法
xArray = window.frames[window.frames.length-1].Array;
//通过构造函数获取⼀个实例
var arr = new xArray(1,2,3);
函数prototype
console.log(String.call(arr) === '[object Array]');//true
4.通过Array.isArray()判断
Array.isArray() ⽤于确定传递的值是否是⼀个数组,返回⼀个布尔值。
let a = [1,2,3]
Array.isArray(a);//true
简单好⽤,⽽且对于多全局环境,Array.isArray() 同样能准确判断,但有个问题,Array.isArray() 是在ES5中提出,也就是说在ES5之前可能会存在不⽀持此⽅法的情况。怎么解决呢?
三、判断数组⽅法的最终推荐
当然还是⽤Array.isArray(),从ES5新增isArray()⽅法正是为了提供⼀个稳定可⽤的数组判断⽅法,不可能专门为此提出的好东西不⽤,⽽对于ES5之前不⽀持此⽅法的问题,我们其实可以做好兼容进⾏⾃⾏封装,像这样:
if (!Array.isArray) {
Array.isArray = function(arg) {
return String.call(arg) === '[object Array]';
};
}