20190219 比较3个判断数组的方法Object.prototype.toString.call() instanceof 、 Array.isArray()

有以下 3 个判断数组的方法,请分别介绍它们之间的区别和优劣

Object.prototype.toString.call() 、 instanceof 、 Array.isArray()

Object.prototype.toString.call()

是原型上提供的判断数据类型的方法。

  • 优点

    可以判断引用类型和基本类型

    Object.prototype.toString.call({0:1}) // "[object Object]"
    Object.prototype.toString.call([0,1]) // "[object Array]"
    Object.prototype.toString.call('1') // "[object String]"
    
  • 缺点

    无法区分出自定义对象。比如:

    class A {};
    class B{};
    let a = new A();
    let b = new B();
    Object.prototype.toString(a); // "[object Object]"
    Object.prototype.toString(b); // "[object Object]"
    

instanceof

通过判断对象的原型链中是不是能找到类型prototype属性。

// __proto__: 代表原型对象链
instance.[__proto__...] === instance.constructor.prototype
// return true
  • 优点
    可以判断自定义对象,
    a instanceof B // false
    a instanceof A // true
    
    可以判断数组
    // instanceof可以区分数组是数组  
    [0,1] instanceof Array // true
    {0:1} instanceof Array // false
    
  • 缺点
    只能用来判断对象类型,无法判断原始类型。比如:
    '1' instanceof String // false
    new String('1') instanceof String // true
    
    所有对象类型 instanceof Object 都是 true。比如:
    [] instanceof Object // true
    new String('1') instanceof Object // true
    

Array.isArray()

用来判断对象是否为数组

// 判断是否是数组
Array.isArray([]); // true
Array.isArray({}); // false
  • 与 instanceof比较
    Array.isArray 优于 instanceof,前者可以检验出原始类型
  • 与 Object.prototype.toString.call()比较
    Array.isArray()是ES5新增的方法,当不存在 Array.isArray() ,可以用 Object.prototype.toString.call() 实现。
    if (!Array.isArray) {
      Array.isArray = function(arg) {
        return Object.prototype.toString.call(arg) === '[object Array]';
      };
    }
    

FAQ

  • 问题一: Object.prototype.toString方法被调用时,都做了哪些事情?
    1. 前置判断
    	  - 如果this的值为undefined,则返回"[object Undefined]"
    	  - 如果this的值为null,则返回"[object Null]"
    2. 获取this对象的[[Class]]属性的值
    3. 计算,返回结果 "[object ", [[Class]]属性值, 以及 "]"
    

toString() 方法与 Object.prototype.toString.call()比较

toString() 是将数据转变成字符串。

var num = 123; num.toString(); // '123'
var obj = {}; obj.toString() // "[object Object]"

FAQ

  • 问题一:原始类型没有属性和方法为什么可以调用toString()方法?

    系统内部会经过包装类进行包装,相当于new Number(num).toString();

    包装类: new Number(); new String(); new Boolean() ;

  • 问题二:包装类也都是对象,为什么调用toString()返回结果不一样?

    原型链终端的Object.prototype对象上的toString()方法确实可以被继承下来,并且可以判断数据类型,
    但不能满足所有的需求,所以子代的包装类数组就重写了自己的toString()方法,
    因此,当我们调用toString()方法时,实际上调用的自身原型上重写的toString()方法。

  • 问题三:为什么判断数据类型时使用Object.prototype.toString.call(xx)而不使用xx.toString?

    xx.toString方法有可能会被改写。不可靠。

补充

typeof的特点

typeof 无法区分出对象和数组

typeof({0:1}) // object
typeof([0,1]) // object

instanceof原理

function instance_of(L, R) {    // L 表示左表达式,R 表示右表达式
  var O = R.prototype;           // 取 R 的显示原型 即:R提供给子级的对象
  L = L.__proto__;               // 取 L 的隐式原型 即:L接收的父级的对象
  while (true) { 
    if (L === null)  return false;
    if (O === L)  return true;   // 这里重点:R提供给子级的对象 = L接收的父级的对象时,则我们认为两者相等。
    L = L.__proto__; 
  } 
}

另附一个全面的判断方法

let class2type = {}
  'Array Date RegExp Object Error'.split(' ').forEach(e => {
    console.log(e, '[object ' + e + ']', e.toLowerCase(),);
    
    class2type[ '[object ' + e + ']' ] = e.toLowerCase()
  }) 
  console.log('class2type', class2type);
  
  function type(obj) {
    if (obj == null) return String(obj)
    console.log(obj);
    
    return typeof obj === 'object' ? 
      class2type[ Object.prototype.toString.call(obj) ] || 'object' : typeof obj
  }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值