• JavaScript中准确的判断数据类型


      在 ECMAScript 规范中,共定义了 7 种数据类型,分为基本类型引用类型两大类。

      其中:

      基本类型:String、Number、Boolean、Symbol、Undefined、Null 

        引用类型:Object

      基本类型也称为简单类型,由于其占据空间固定,是简单的数据段,为了便于提升变量查询速度,将其存储在栈(stack)中,即按值访问

      引用类型也称为复杂类型,由于其值的大小会改变,所以不能将其存放在栈中,否则会降低变量查询速度,因此,其值存储在堆(heap)中,而存储在变量处的值,是一个指针,指向存储对象的内存处,即按址访问。引用类型除 Object 外,还包括 Function 、Array、RegExp、Date 等等。

      下面介绍常用的4种判断数据类型的方法,并对各个方法存在的问题进行简单的分析。

    一、typeof

       typeof 是一个操作符,其右侧跟一个一元表达式,并返回这个表达式的数据类型。

      返回的结果用该类型的字符串(全小写字母)形式表示,包括以下 7 种:string、number、boolean、symbol、undefined、object、function 等。

    typeof 'a'; // string 有效
    typeof 1; // number 有效
    typeof true; //boolean 有效
    typeof Symbol(); // symbol 有效
    typeof undefined; //undefined 有效
    typeof new Function(); // function 有效
    typeof null; //object 无效
    typeof [1] ; //object 无效
    typeof new RegExp(); //object 无效
    typeof new Date(); //object 无效

      总结:

    • 对于基本类型,除 null 以外,均可以返回正确的结果。
    • 对于引用类型,除 function 以外,一律返回 object 类型。
    • 对于 null ,返回 object 类型。
    • 对于 function 返回  function 类型。

      其中,null 有属于自己的数据类型 Null ,引用类型中的数组、日期、正则 也都有属于自己的具体类型,而 typeof 对于这些类型的处理,只返回了处于其原型链最顶端的 Object 类型。

    二、instanceof

      instanceof 检测的是原型,表达式为:A instanceof B,如果 A 是 B 的实例,则返回 true,否则返回 false。

    [] instanceof Array; // true
    new Date() instanceof Date;// true
     
    function Person(){};
    new Person() instanceof Person;//true
     
    [] instanceof Object; // true
    new Date() instanceof Object;// true
    new Person instanceof Object;// true

      虽然 instanceof 能够判断出 [ ] 是Array的实例,但它认为 [ ] 也是Object的实例,为什么呢?

       从 instanceof 能够判断出 [ ].__proto__  指向 Array.prototype,而 Array.prototype.__proto__ 又指向了Object.prototype,最终 Object.prototype.__proto__ 指向了null,标志着原型链的结束。因此,[ ]、Array、Object 就在内部形成了一条原型链,如下图所示:

       从原型链可以看出,[] 的 __proto__  直接指向Array.prototype,间接指向 Object.prototype,所以按照 instanceof 的判断规则,[] 就是Object的实例。依次类推,类似的 new Date()、new Person() 也会形成一条对应的原型链 。

      因此,instanceof 只能用来判断两个对象是否属于实例关系, 而不能判断一个对象实例具体属于哪种类型 

        针对数组的这个问题,ES5 提供了 Array.isArray() 方法 。该方法用以确认某个对象本身是否为 Array 类型,而不区分该对象在哪个环境中创建。

    if (Array.isArray(value)){
       //对数组执行某些操作
    }

      Array.isArray() 本质上检测的是对象的 [[Class]] 值

      [[Class]] 是对象的一个内部属性,里面包含了对象的类型信息,其格式为 [object Xxx],Xxx 就是对应的具体类型 。对于数组而言,[[Class]] 的值就是 [object Array] 。

    三、constructor

      当一个函数 F被定义时,JS引擎会为F添加 prototype 原型,然后再在 prototype上添加一个 constructor 属性,并让其指向 F 的引用。如下图所示:

       当执行 var f = new F() 时,F 被当成了构造函数,f 是F的实例对象,此时 F 原型上的 constructor 传递到了 f 上,因此 f.constructor == F

      可以看出,F 利用原型对象上的 constructor 引用了自身,当 F 作为构造函数来创建对象时,原型上的 constructor 就被遗传到了新创建的对象上, 从原型链角度讲,构造函数 F 就是新对象的类型。这样做的意义是,让新对象在诞生以后,就具有可追溯的数据类型。 

      同样,JavaScript 中的内置对象在内部构建时也是这样做的,如下图所示。

      总结:

      1. null 和 undefined 是无效的对象,因此是不会有 constructor 存在的,这两种类型的数据需要通过其他方式来判断。

      2. 函数的 constructor 是不稳定的,这个主要体现在自定义对象上,当开发者重写 prototype 后,原有的 constructor 引用会丢失,constructor 会默认为 Object。

    四、toString

      toString() 是 Object 的原型方法,调用该方法,默认返回当前对象的 [[Class]] 。这是一个内部属性,其格式为 [object Xxx] ,其中 Xxx 就是对象的类型。

      对于 Object 对象,直接调用 toString()  就能返回 [object Object] 。而对于其他对象,则需要通过 call / apply 来调用才能返回正确的类型信息。

      语法:Object.prototype.toString.call(value);

    Object.prototype.toString.call('') ;   // [object String]
    Object.prototype.toString.call(1) ;    // [object Number]
    Object.prototype.toString.call(true) ; // [object Boolean]
    Object.prototype.toString.call(Symbol()); //[object Symbol]
    Object.prototype.toString.call(undefined) ; // [object Undefined]
    Object.prototype.toString.call(null) ; // [object Null]
    Object.prototype.toString.call(new Function()) ; // [object Function]
    Object.prototype.toString.call(new Date()) ; // [object Date]
    Object.prototype.toString.call([]) ; // [object Array]
    Object.prototype.toString.call(new RegExp()) ; // [object RegExp]
    Object.prototype.toString.call(new Error()) ; // [object Error]
    Object.prototype.toString.call(document) ; // [object HTMLDocument]
    Object.prototype.toString.call(window) ; //[object global] window 是全局对象 global 的引用
  • 相关阅读:
    进度三
    centos7 安装nodejs 最新版及yarn安装
    sed -i 增加或删减注释#
    解决go编译报错../github.com/golang/freetype/truetype/face.go:13:2: cannot find package "golang.org/x/image/font" in any of:
    解决go打包时报错 models/util/code.go:23:2: cannot find package "github.com/boombuler/barcode" in any of:
    Dockerfile文件说明
    docker exec 报错:error: code = 13 desc = invalid header field value "oci runtime error
    Docker中 /var/lib/docker/overlay2/磁盘爆满,如何解决?
    CentOS7默认安装的/home中转移空间到根目录/
    Docker存储驱动之--overlay2
  • 原文地址:https://www.cnblogs.com/gg-qq/p/10815109.html
Copyright © 2020-2023  润新知