最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • 数据类型检测

    正文概述 掘金(从0开始学JS)   2021-07-23   432

    数据类型

    • 原始值类型「值类型/基本数据类型」
      • Number 数字
      • Boolean 布尔
      • String 字符串
      • Null 空对象指针
      • Undefined 未定义
      • Symbol 唯一值 ???
      • Bigint 大数 ???
    • 对象类型「引用数据类型」
      • 标准普通对象 object
      • 标准特殊对象 Array、RegExp、Date、Math、Error……
      • 非标准特殊对象 Number、String、Boolean……
      • 可调用/执行对象「函数」function

    常用的数据类型检测方法有哪些?

    1. typeof 运算符

    语法:

    var str = typeof [value]
    

    作用: 用来检测给定变量的数据类型

    返回值: 一个字符串,字符串中包含了对应的数据类型 。

    始终返回以下某个字符串:

    • 'undefined' => 值未定义
    • 'boolean' => 布尔值
    • 'number' => 数值
    • 'string' => 字符串
    • "symbol" =>唯一值
    • 'bignit' => 大数
    • 'function' => 函数是一种对象,不是一种数据类型
    • 'object' => 被检测的值是对象或者null

    原理(底层机制): 所有数据类型的值在存储时,在计算机底层都是按照“二进制”来存储的「64位」

    typeof 检测数据类型,就是按照存储的“二进制值”来进行检测的, 比如:

    • 000 开头的 => 对象
    • 1 开头的 => 整数
    • 010 开头的 => 浮点数
    • 100 开头的 => 字符串
    • 110 开头的 => 布尔值
    • 000000…. => null

    如值的前三位是 000 的,都被认为是对象。在这个基础上,再检测对象内部是否实现了[[Call]]方法

    • 实现了,则认为是函数,返回“function”。
    • 没有实现,则都返回 "object"。

    优点:

    • 因为 typeof 检测数据类型,就是按照存储的“二进制值”来进行检测的,因此使用 typeof 检测数据类型的时候,性能相对好一些。
    • 在检测原始值类型的值( null 除外)时,结果都是准确的。

    缺点(局限性):

    • 使用 typeof 检测 null 时返回的是 'object'
    • 使用 typeof 检测对象类型的值时,不能细分对象。除函数对象返回“function”外,其他的对象类型值返回的都是“object”。
    • 使用 typeof 检测一个未被声明的变量,不会报错,而是返回“undefined”。

    2. instanceof 操作符

    语法:

    var result = value instanceof Ctor
    // Ctor => constructor  构造函数
    

    作用:
    检测某个实例是否属于这个类。可以弥补 typeof 的不足,把对象类型进行细分。

    返回值:

    • true => 实例属于这个类
    • false => 实例 不属于这个类

    原理(底层机制):
    基于 instanceof 检测的时候,先看 Ctor 构造函数是否存在 Symbol.hasInstance 这个属性方法,

    • 如果存在则基于这个方法进行检测,则调用 Ctor[Symbol.hasInstance](value)
    • 如果没有这个属性方法,获取value的原型链(直到找到Object.prototype为止)
      • 如果 Ctor.prototype 出现在它的原型链上,则证明value是Ctor的实例,
      • 反之则不是...
    • 在新版本浏览器中,在 Function.prototype 上存在一个属性方法 Symbol.hasInstance,所以只要是函数「不论是普通函数,还是构造函数」,都具备 Symbol.hasInstance 这个方法...

    缺点(局限性):

    • instanceof 来检测数据类型,就是临时“凑个数”,所以答案仅供参考。
    • instanceof 检测任何引用值 和 Object 构造函数都会返回 true。因为所有引用值都是 Object 的实例。
    • instanceof 检测原始值,则始终会返回 false,因为原始值不是对象。

    例1:

    let n = [];
    console.log(n instanceof Array); //true
    console.log(n instanceof RegExp); // false
    console.log(n instanceof Object); //true  所有引用值都是 Object 的实例。
    

    例2:

    自定义构造函数,如果借用其他构造函数的原型对象,会致使检测结果不准。

    下面代码中的构造函数 Fn ,借用了 Array.prototype。

    function Fn() {}
    Fn.prototype = Array.prototype;
    let f = new Fn;
    console.log(f instanceof Array); // true  检测结果不准了。
    

    例3:

    内置类的 Symbol.hasInstance 属性,重写是无效的

    
    Array[Symbol.hasInstance] = function () {
        return 100;
    };
    let n = [];
    console.log(n instanceof Array);  //=> true
    

    例4:

    自定义构造函数,可以指定 Symbol.hasInstance 属性。可能会致使检测结果不准。

    class Fn {
        static[Symbol.hasInstance](val) {
            return false;
        }
    }
    let f = new Fn; // f 是构造函数  Fn 的实例
    console.log(f instanceof Fn); //false
    console.log(Fn[Symbol.hasInstance](f)); //false
    

    3. constructor

    语法:

    var result = 实例对象.constructor ;
    

    作用: 获取实例的构造函数。

    返回值: 实例对象所属的构造函数(堆地址)

    原理(底层机制):

    大多数函数都有一个 prototype 属性(原型对象),其下面有个 constructor 属性。

    默认情况下,constructor 属性指回与之关联的构造函数。

    缺点(局限性):

    • constructor 来检测数据类型也是临时拉来凑数的,所以也不靠谱。
    • constructor 属性的指向可以被肆意更改。
    • null 在访问 constructor 属性时,会报错。

    例1:

    可以用 constructor检测一个对象是否为标准普通对象「纯粹对象」, 是否为 Object 的直属实例。

    n 是 Array 的直属实例, 而不是 RegExp 和 Object 的直属实例。

    let n = [];
    console.log(n.constructor === Array); // true
    console.log(n.constructor === RegExp); // false
    console.log(n.constructor === Object);  // false
    

    例2:

    使用原始值访问constructor 属性时,会默认进行“装箱”操作。

    所谓“装箱”是指原始值转换为其构造函数创造的对象类型实例,从而原始值就可以调用所属类原型上的方法了。

    let n = 1;
    console.log(n.constructor === Number);
    // true
    //  把原始值的1默认变为对象类型的实例 new Number(1)
    

    例3:

    修改了 constructor 属性的指向 ,检测结果不准了

    let n = [];
    Array.prototype.constructor = 'AAA'; //=>false
    console.log(n.constructor === Array);
    

    例4:

    null 在访问 constructor 属性时,会报错

    (null).constructor
    // Uncaught TypeError: Cannot read property 'constructor' of null
    

    4. Object.prototype.toString.call([value])

    语法:

    作用: 大部分类的原型上都有toString方法,都是用来转换为字符串的...

    但是Object.prototype.toString不是用来转换为字符串的,而是检测数据类型的

    返回值: “[object ?]”

    原理(底层机制): 先检查[value][Symbol.toStringTag]属性,

    • 如果有这个属性,属性值是啥 @X,最后检测的结果就是 “[object @X]”。
      • 如果没这个属性,则按照自己所属的内置类进行处理

    优点:

    这个方法忒好用了...除了写起来麻烦一些,几乎没有漏洞

    例1:

    调用 Object.prototype.toString() 时,方法中的this是谁,就是检测谁的数据类型

    // 1.
    let obj = {
        name: 'xiaoming'
    }
    console.log(obj.toString());
    //=> "[object Object]" -> Object.prototype.toString
    
    
    // 2. 通过 call() 改变方法执行时的 this 指向
    Object.prototype.toString.call([10, 20])
    // =>"[object Array]"
    
    // 3.  实际开发中,为了简化代码,还会这样写
    let obj = {},
        toString = obj.toString; // => Object.prototype.toString
    console.log(toString.call(1)); // => "[object Number]"
    

    例2:

    Number.prototype.toString 把数组实例 转换为字符串

    • 数字.toString() 把数字转换为字符串
    • 数字.toString(radix) 把数字转换为radix进制值的字符串
    // 不指定 radix, 默认为十进制数
    console.log((2).toString());
    // "2"
    
    // 指定 radix 为 2, 先把数值转为2进制数,再转成字符串
    console.log((2).toString(2));
    // "10"
    

    例3:

    console.log([10, 20, 30].toString());
    //-> "10,20,30" -> Array.prototype.toString
    
    

    例4:

    为自定义构造函数的原型对象上添加属性 Symbol.toStringTag

    class Fn {
        constructor() {
            this.name = 'zhufeng';
            this[Symbol.toStringTag] = 'Fn';
        }
    }
    let f = new Fn;
    console.log(toString.call(f)); //=>“[object Fn]”
    

    封装几个用于数据检测的函数

    1. 检测是否是一个函数

    var isFunction = function isFunction(obj) {
        return typeof obj === 'function' && typeof obj.nodeType !== "number" &&  typeof obj.item !== "function"
    }
    

    第一个条件 typeof obj === 'function' ,已经判断出obj是函数了,为什么还要加 2 个判断条件呢? 那是为了处理两个兼容问题:

    1. typeof document.createElement("object")==="function"

    2. typeof document.getElementsByTagName("div")==="function"

       在 HTML 中有个` <object>` 元素。使用<object> 元素可在 HTML 加入 Flash 文件。有些浏览器会判定<object> 元素为函数,所以我们需要排除 <object> 元素。那么如何才能排除呢?
       在 JavaScript中,所有 DOM 节点类型都继承 Node 类型。也就是说每个 DOM 节点都能访问到 Node.prototype 上的属性和方法。而 Node.prototype 上就有一个 nodeType 属性,表示该节点的类型。节点类型由定义在 Node 类型上的 12 个数值常量表示。所以不管是什么类型的节点,返回的值类型都是 'number',即 `typeof obj.nodeType !== "number"` 。
      
      
       通过 `document.getElementsByTagName() ` 获取到的是一个 `HTMLCollection` 元素的集合。
       `HTMLCollection` 提供了用来从该集合中选择元素的方法和属性。
       其中有个静态方法 item(),其作用是根据给定的索引(从0开始),返回具体的节点。
      

    2. 检测是否 window 对象

    const isWindow = function isWindow(obj) {
            return obj !=null && obj === obj.window
        }
    

    3. 检测数据类型的方法(十八项全能)

    
    let toString = {}.toString;
    // {}.toString => Object.prototype.toString
    
    const toType = function toType(obj) {
            let reg = /^\[object ([0-9a-zA-Z]+)\]$/;
            // null & undefined
            if (obj == null) return obj + '';
            // 其他类型的
            return typeof obj === 'object' || typeof obj === 'function' ? reg.exec(toString.call(obj))[1].toLowerCase() : typeof obj ;
        }
    
    console.log(toType(0)); // 'number'
    console.log(toType(/^$/));  // 'regexp'
    

    起源地下载网 » 数据类型检测

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元