美文网首页
Javascript 数据类型检测及原理

Javascript 数据类型检测及原理

作者: Nevermind | 来源:发表于2019-06-09 18:02 被阅读0次

    前言

    数据类型检测是 JavaScript 中既基础又考验原理的知识,如果你对 JavaScript 数据类型检测还不清楚,那么这篇文章应该会帮到你。

    一、typeof

    返回所属类型的字符串格式。但不能判断 object 类型下具体的数据结构,是普通对象、Array 或 Date 等。

    // "number"
    typeof 123         
    typeof NaN
    
    typeof "123"        // "string"
    typeof true         // "boolean"
    typeof undefined    // "undefined"
    
    // "symbol"
    typeof Symbol('a')     
    typeof Symbol.iterator 
    
    // "object"
    typeof {a:1}       
    typeof [1,2,3]   
    typeof null        
    typeof new Date() 
    typeof new Number(1)  
    
    // "function"
    function aaa(){}
    typeof aaa         
    typeof new Function()
    

    为什么 typeof null === "object"

    在 JavaScript 最初实现中,JavaScript 是由一个表示类型的标签和实际数据值表示,对象的类型标签是 0。null 代表空指针,在大多数平台下值为 0x00,因此 null 的类型标签也成了0。

    为什么 typeof new String('abc') === "object"

    首先涉及到装箱转换的概念

    每种基本数据类型在对象中都有对应的类。装箱转换就是将基本类型转换成对应的对象

    new String('abc') 是将基本字符串装箱转换成字符串对象,所以返回"object"
    我们可以通过 valueOf() 方法将字符串对象转换回基本字符串。

    二、 instanceof

    obj instanceof Foo检测构造函数的 prototype 是否出现在对象原型链中的任何位置。
    问题1:由于是使用原型链查找机制,所以不能检测基本数据类型。
    问题2: Foo.prototype 的值和 obj.__proto__ 都可能发生改变,导致检测结果不正确

    function D(){}
    function C(){}
    let c = new C();
    let d = new D()
    c instanceof C  // true
    d instanceof D  // true
    
    // 修改 d.__proto__
    Object.setPrototypeOf(d, C.prototype)   
    d instanceof D  // false
    d instanceof C  // true
    
    // 修改 C.prototype
    C.prototype = {};
    c instanceof C  // false
    
    

    扩展
    使用 Symbol.hasInstance 可以自定义 instanceof 在某个类上的行为

    class MyArray {  
      static [Symbol.hasInstance](instance) {
        return Array.isArray(instance);
      }
    }
    console.log([] instanceof MyArray); // true
    

    三、Object.prototype.toString.call()

    Symbol.toStringTag
    Symbol.toStringTag 通常作为对象的属性使用,属性值是字符串类型,表示对象的自定义类型标签。Object.prototype.toString() 方法会读取这个标签,并包含在返回值中。

    原理
    这个方法会获取 this 对象的 [[class]]私有属性(ES6之后获取Symbol.toStringTag属性),然后包装进[object, ]返回

    自定义的类,需要通过Symbol.toStringTag 属性设置类型标签后,才能返回正确的类

    // 第一种情况
    class Person{
        get [Symbol.toStringTag](){
            return 'Person'
        }
    }
    
    let p = new Person();
    Object.prototype.toString.call(p);  // "[object Person]"
    p.toString();                       // "[object Person]"
    
    
    // 第二种情况
    class Person{
        get [Symbol.toStringTag](){
            return 'Person'
        }
        toString() {
           return 'abc';
        }
    }
    
    let p = new Person();
    Object.prototype.toString.call(p); // "[object Person]"
    p.toString()                       // "abc"
    

    对比以上两种情况,实例调用toString方法时,会先检测当前类的原型上是否有 toString() 方法,有则调用,没有则调用父类的toString()方法。所以第一种情况返回的结果和Object.prototype.toString.call(p) 执行结果一致。
    所以我们一般使用Object.prototype.toString.call() 来检测数据类型而不是通过实例直接调用 toString()方法,是防止类重写 toString()方法。

    相关文章

      网友评论

          本文标题:Javascript 数据类型检测及原理

          本文链接:https://www.haomeiwen.com/subject/utunxctx.html