问题描述
在js中判断数据类型通常使用typeof,但是typeof在判断数组和对象时的结果都是object。
console.log(typeof []);
console.log(typeof {});
那么,怎么才能区分对象和数组呢?
方法
- 判断原型
var obj = {};
var arr = [];
console.log(arr);
console.log(obj);
由上图可知,数组和对象的原型对象不一样,由此可以通过判断原型来判断一个对象是否为数组
var obj = {};
var arr = [];
console.log(Object.getPrototypeOf(obj) === Object.prototype);
console.log(Object.getPrototypeOf(obj) === Array.prototype);
由此可以得知此种方法可行,但是这种方法是通过检查原型来判断是否为数组,而原型又是可以人为改变的一旦原型改变就可能会失效。
var obj = {};
var arr = [];
Object.setPrototypeOf(obj, Array.prototype);
console.log(Object.getPrototypeOf(obj) === Object.prototype);
console.log(Object.getPrototypeOf(obj) === Array.prototype);
此时arr的原型不是Array.prototype第一个返回的结果为false如此,不能判断是否为数组。
- 判断构造函数
创建对象和创建数组的构造函数不同可以通过此种方法判断一个对象是否为数组。
var obj = {};
var arr = [];
console.log(Object.getPrototypeOf(obj).constructor === Object);
console.log(Object.getPrototypeOf(obj).constructor === Array);
由此可见,两个输出结果并不一样,并且也符合我们的认知,通过此种方法也可以判断一个对象是否为数组。
但该种方法与上一种方法的问题一样即当构造函数被修改之后就无法判断真正的数组。
var obj = {};
var arr = [];
Object.getPrototypeOf(obj).constructor = Array;
console.log(Object.getPrototypeOf(obj).constructor === Object);
console.log(Object.getPrototypeOf(obj).constructor === Array);
console.log(Object.getPrototypeOf(arr).constructor === Array);
由此可见,该方法的缺与上一种方法的一样。
在判断构造函数方法中除了直接判断外还可以使用 instanceof 判断一个对象是否为一个构造函数的实例
var obj = {};
var arr = [];
console.log(obj instanceof Array);
console.log(arr instanceof Array);
由此可见,该方法也可以判断是否为数组。
3. Array.isArray()
通过Array.isArray()可以判断一个对象是否为数组。
var obj = {};
var arr = [];
console.log(Array.isArray(obj));
console.log(Array.isArray(arr));
由此可见此种方法可行,那么当我们把其构造函数改变后还会出现和上面一样的情况吗?
var obj = {};
var arr = [];
Object.getPrototypeOf(obj).constructor = Array;
console.log(Array.isArray(obj));
console.log(Array.isArray(arr));
由此可见,即便将obj的构造函数改为Array也能判断出真正的数组。
4. 用Object.toString()方法判断
var obj = {};
var arr = [];
console.log(obj.toString());
console.log(arr.toString());
由此可见对象是Object创建的,但是数组的toString()返回的是空。
这是因为js中每个对象都有toString()方法,该方法继承自Object.toString()方法,但数组被重写了,但是我们可以使用call()来调用数组的toString的原始方法来判断。
var obj = {};
var arr = [];
console.log(obj.toString());
console.log(Object.prototype.toString.call(arr));
由此可见,也可以通过此种方法判断一个对象是否为数组。
那么,如果改变构造函数是否会发生类似之前的情况呢?
var obj = {};
var arr = [];
Object.getPrototypeOf(obj).constructor = Array;
console.log(obj.toString());
console.log(Object.prototype.toString.call(arr));
由此可见,此时还能正常判断并不会发生此前出现的情况。
使用场景
判断一个对象是否为数组在什么地方使用呢
在进行克隆时,需要判断对象的属性是否为数组,根据结果采取不同的操作。
总结
- 判断原型和判断构造函数的方法的结果会因为原型和构造函数的改变发生改变,并不十分稳定。
- Array,isArray()和Object.toString()方法较为稳定,较为推荐。
- 通常在进行克隆时会用到判断一个对象是否为数组。