MLuminary/Blog

对象类型的鉴别

MLuminary opened this issue · 0 comments

判断一个对象是不是数组类型

typeof

少部分人可能首先会想到 typeof

var n = 3,
  b = true,
  s = 'Hello',
  x = null,
  y,
  obj1 = function() {},
  obj2 = {},
  obj3 = [],
  obj4 = new Date();
console.log(
  typeof n, //number
  typeof b, //boolean
  typeof s, //string
  typeof x, //object
  typeof y, //undefined
  typeof obj1, //function
  typeof obj2, //object
  typeof obj3, //object
  typeof obj4 //object
);

可以看出 typeof 是可以判断出基本数据类型的,函数也能判断出来,但是对象、数组、日期都会返回 object,这样就根本无法判断一个对象是不是数组类型。所以 typeof 宣告无能为力

判断其父级原型对象

var obj1 = {},
  obj2 = [1, 2, 3],
  obj3 = new Date();

console.log(obj1.__proto__ == Array.prototype); //false
console.log(obj2.__proto__ == Array.prototype); //true
console.log(obj3.__proto__ == Array.prototype); //false

但是 __proto__ 是内部属性,本不应该被访问到,我们可以用 Object.getPrototypeOf(obj) 方法来代替他,虽然这个方法其实内部原理也是他,但是还是有不同的。

console.log(Object.getPrototypeOf(obj1) == Array.prototype); //false
console.log(Object.getPrototypeOf(obj2) == Array.prototype); //true
console.log(Object.getPrototypeOf(obj3) == Array.prototype); //false

判断其构造函数

obj instanceof Array 判断 obj 是不是被构造函数 Array 创造出来的

console.log(obj1 instanceof Array); //false
console.log(obj2 instanceof Array); //true
console.log(obj3 instanceof Array);	//false

instanceof 不仅判断直接父类型,而是所有在原型链上的类型,都返回 true ,所以如果你创建一个对象但是把他的 __proto__ 指向 Array 的原型,然后判断其类型,也会返回 true

obj1.__proto__ = Array.prototype;
console.log(obj1 instanceof Array); //true

判断对象内部的 class 属性

每个对象内部,都有一个隐藏的 class 属性,记录该对象创建时的数据类型 class 属性不会随继承关系的改变而改变。(就相当于查人的 DNA 了吧,小样还想伪装。)

这里有一个问题:内置类型的原型对象中几乎都重写了新的 toString(),只有最顶层的 toString() 才能输出对象的 class 属性值,

因此我们可以用 call 来使用最牛皮的身份鉴别

console.log(
  Object.prototype.toString.call(obj1) == /*[object Object]*/ '[object Array]'
); //false
console.log(
  Object.prototype.toString.call(obj2) == /*[object Array]*/ '[object Array]'
); //true
console.log(
  Object.prototype.toString.call(obj3) == /*[object Date]*/ '[object Array]'
); //false

Array.isArray

Array.isArray 也可以弥补 typeof 的不足

Array.isArray(obj1); //false
Array.isArray(obj2); //true
Array.isArray(obj3); //false