判断一个变量是数组还是对象
我们都知道数组也是属于对象,因此用一般的typeof 无法达到预期效果:
例如:
var a = [1, 2, 3];
console.log(typeof a);//object,
此时需要其他方法才能判断:
1.instanceof运算符
instanceof运算符用于通过查找原型链来检测某个变量是否为某个类型数据的实例,使用instanceof运算符可以判断一个变量是数组还是对象。
var a = [1, 2, 3];
console.log(a instanceof Array); // true
console.log(a instanceof Object); // true
var b = {name: 'kingx'};
console.log(b instanceof Array); // false
console.log(b instanceof Object); // true
通过上面代码可以发现,数组不仅是Array类型的实例,也是Object类型的实例。因此我们在判断一个变量是数组还是对象时,应该先判断数组类型,然后再去判断对象类型。如果先判断对象,那么数组值也会被判断为对象类型,这无法满足要求。
我们可以得到以下的封装函数。
// 判断变量是数组还是对象 function getDataType(o) { if (o instanceof Array) { return 'Array' } else if (o instanceof Object) { return 'Object'; } else { return 'param is not object type'; } }
2.判断构造函数
判断一个变量是否是数组或者对象,从另一个层面讲,就是判断变量的构造函数是Array类型还是Object类型。因为一个对象的实例都是通过构造函数生成的,所以,我们可以直接判断一个变量的constructor属性。
var a = [1, 2, 3];
console.log(a.constructor === Array); // true
console.log(a.constructor === Object); // false
var b = {name: 'kingx'};
console.log(b.constructor === Array); // false
console.log(b.constructor === Object); // true
那么一个变量为什么会有constructor属性呢?这就要涉及原型链的知识了。
每个变量都会有一个__proto__属性,表示的是隐式原型。一个对象的隐式原型指向的是构造该对象的构造函数的原型,这里用数组来举例,代码如下所示。
[]._ _proto_ _ === [].constructor.prototype; // true
[]._ _proto_ _ === Array.prototype; // true
我们可以将上面代码进行封装,得到一个判断变量是数组还是对象的通用函数。
function getDataType(o) { // 获取构造函数 var constructor = o._ _proto_ _.constructor || o.constructor; if (constructor === Array) { return 'Array'; } else if (constructor === Object) { return 'Object'; } else { return 'param is not object type'; } }
3. toString()函数
每种引用数据类型都会直接或间接继承自Object类型,因此它们都包含toString()函数。不同数据类型的toString()函数返回值也不一样,所以通过toString()函数就可以判断一个变量是数组还是对象。
这里我们会借助call()函数,直接调用Object原型上的toString()函数,把主体设置为需要传入的变量,然后通过返回值进行判断。
var a = [1, 2, 3];
var b = {name: 'kingx'};
console.log(Object.prototype.toString.call(a)); // [object Array]
console.log(Object.prototype.toString.call(b)); // [object Object]
其实任何类型的变量在调用toString()函数时,都会返回不同的结果。
Object.prototype.toString.call(1); // [object Number]
Object.prototype.toString.call('kingx'); // [object String]
var c;
Object.prototype.toString.call(c); // [object Undefined]
通过返回的结果字符串来判断,即可解决这个问题。我们将代码进行如下封装。
// 判断变量是数组还是对象 function getDataType(o) { var result = Object.prototype.toString.call(o); if (result === '[object Array]') { return 'Array'; } else if (result === '[object Object]') { return 'Object'; } else { return 'param is no object type'; } }
4.Array.isArray()函数
在JavaScript 1.8.5版本中,数组增加了一个isArray()静态函数,用于判断变量是否为数组。传入需要判断的变量,即可确定该变量是否为数组,使用起来很简单。
// 下面的函数调用都返回“true”
Array.isArray([]);
Array.isArray([1]);
Array.isArray(new Array());
// 鲜为人知的事实:其实 Array.prototype 也是一个数组。
Array.isArray(Array.prototype);
// 下面的函数调用都返回“false”
Array.isArray();
Array.isArray({});
Array.isArray(null);
Array.isArray(undefined);
Array.isArray(17);
Array.isArray('Array');
Array.isArray(true);
使用Array.isArray()函数只能判断出变量是否为数组,并不能确定是否为对象。