面试官:JS判断数据类型,原理?

675 阅读3分钟

关于js判断数据类型,会,但好像又不是完全会,在面试中总是被一些奇怪的问题搞得很狼狈。

但是有了这篇文章,妈妈再也不用担心面试被问到数据类型的问题了。

First blood

面试官:可以说一下js判断数据类型的方法吗?

我:判断基本数据类型可以用typeof,判断复杂数据类型可以用instanceof,它主要通过判断前者否为后者的实例对象来实现的。同时也可以使用Object.prototype.toString.call()方法和构造函数constructor来判断数据类型。

面试官:哦?那你知道instanceof是怎么判断前者是否为后者的实例化对象的吗,可以自己实现出来吗。

我:(自己写?请问您礼貌吗,还好我有所准备,根本没在怕的)

首先,a instanceof A ,主要是通过在a的原型链上一层一层去找,如果能找到A.prototype,就说明a是A的实例化对象。如果找到头都没有找到A.prototype,那就说明a不是A的实例化对象。那怎么能知道找到头呢?因为所有对象从原型链向上找,最后一个一定是null,倒数第二个是Object。所以我们可以说所有的对象都是Object的实例化对象。

如果不够清楚我们可以举个例子,例如我们创建一个数组的对象,我们看一下它的原型链的情况:

let arr = new Array()
arr.__proto__ === Array.prototype // true
arr.__proto__.__proto__ === Object.prototype // true
arr.__proto__.__proto__.__proto__ === null // true

有了这个思路我们就可以手动自己写一个instanceof方法了。

function myInstanceof(left,right){
    if(typeof left !== 'object' || left === null){
        return false;
    }
    let leftProto = left.__proto__
    let rightProto = right.prototype
    while(true){
        if(leftProto === null){
            return false
        }
        if(leftProto === rightProto){
            return true
        }
        leftProto = leftProto.__proto__
    }
}

Double kill

面试官:说得不错,那你刚才说的Object.prototype.toString.call()是怎么做到能判断数据类型的呢?其中的prototype和call都是用来做什么的。

我:(够刁钻,但是我依旧可以的)

首先说一下为什么要以Object.prototype的这种写法,因为对于一些像数组,字符串类型的,它们已经重写了toString()方法

console.log('123'.toString()); // 123
console.log([1,2,3].toString()); //1,2,3

所以我们才使用Object.prototype.toString()这种保险的方式来写。而这个方法会根据this来返回一个像'[object xxx]'这种形式的字符串,后面这个xxx就是this对象的类型。如果直接调用,那么就是Object的类型,返回的值也就是'[object Object]'

如果想要判断其他类型的对象,我们只要改变了调用这个方法的this对象,就可以获得改变后对象的类型了,那如何改变this的指向呢?我们可以在方法的后面加上一个call方法。

    Object.prototype.toString.call('') ;   // [object String]
    Object.prototype.toString.call(1) ;    // [object Number]
    Object.prototype.toString.call(true) ; // [object Boolean]
    Object.prototype.toString.call(undefined) ; // [object Undefined]
    Object.prototype.toString.call(null) ; // [object Null]
    Object.prototype.toString.call({}) ; // [object Object]
    Object.prototype.toString.call([]) ; // [object Array]
    Object.prototype.toString.call(new Function()) ; // [object Function]
    Object.prototype.toString.call(new Date()) ; // [object Date]
    Object.prototype.toString.call(new RegExp()) ; // [object RegExp]
    Object.prototype.toString.call(new Error()) ; // [object Error]

Triple kill

面试官:答的不错,那我给你出几个题做吧。都是和数据类型相关的,做一下试试

console.log(true + 0);
console.log(true + 'abc');
console.log(true+true);
console.log(true+false);
console.log(null + 1);
console.log(undefined + 1);
console.log(undefined + '123');
console.log('1'>true);
console.log('3'>true);
console.log(1+'2'+false);
console.log('2' + ['arr',1]);
console.log(NaN == NaN);
console.log(null == undefined);
console.log(null === undefined);
console.log(1 == true);
console.log(0 === false);
var p1 = {
    name: 'lisi',
    age: 20
}

var p2 = {
    toString(){
        return 'name:wangwu,age:18'
    }
}

console.log('嘻嘻' + p1);
console.log('哈哈' + p2);

我:👴不做