上一主题 下一主题
ScriptCat,新一代的脚本管理器脚本站,与全世界分享你的用户脚本油猴脚本开发指南教程目录
返回列表 发新帖

[JavaScript基础] 如何判断一个值的类型

[复制链接]
  • TA的每日心情
    难过
    2024-4-24 18:57
  • 签到天数: 13 天

    [LV.3]偶尔看看II

    24

    主题

    31

    回帖

    281

    积分

    荣誉开发者

    积分
    281

    荣誉开发者油中2周年生态建设者喜迎中秋

    发表于 2023-9-29 21:56:34 | 显示全部楼层 | 阅读模式

    本帖最后由 Yiero 于 2023-9-30 14:13 编辑

    如何判断一个值的类型

    本章内容:

    • 使用 typeof 判断基本类型
    • 使用 Object.prototype.toString.call() 判断对象类型
    • 通过类属性 Symbol.toStringTag , 让自定义类也能输出类型
    • 改变原生对象的类型

    1. 基础类型判断

    Js 提供了一个类型判断关键字 typeof, 使用该关键字可以输出基本类型的类型字符串, 比如 typeof 'hello' 会输出字符串 'string'.

    这个关键字只能判断 js 中的八个数据类型还有函数: number, string, boolean, undefined, symbol, bigint, object , nullfunction .

    需要注意的是 typeof null 输出的是 'object' 而不是 null, 如果要判断 null 需要使用后面第三节的内容.

    /* 数字类型 */
    console.log('数字类型: ', typeof 1);
    // -> 数字类型: number
    
    /* 字符串类型 */
    console.log('字符串类型: ', typeof 'hello');
    // -> 字符串类型: string
    
    /* 布尔类型 */
    console.log('布尔类型: ', typeof true);
    // -> 布尔类型: boolean
    
    /* undefined类型 */
    console.log('undefined类型: ', typeof undefined);
    // -> undefined类型: undefined
    
    /* Symbol类型 */
    console.log('Symbol类型: ', typeof Symbol("hello"));
    // -> Symbol类型: symbol
    
    /* BigInt类型 */
    console.log('BigInt类型: ' ,typeof BigInt(123));
    // -> BigInt类型: bigint
    
    /* Object类型 */
    console.log('Object类型: ',typeof {});
    // -> Object类型: object
    
    /* null类型 */
    console.log('null类型: ', typeof null);
    // -> null类型: object
    
    /* function类型 */
    console.log( 'function类型: ', typeof function () {} );
    // -> function类型: function

    2. typeof 的弊端

    typeof 只能判断 原始值 , 也就是上文中提到的除了 Objectnull 以外的类型, 因为除了原始值, 其它的任何类型 (引用类型) 都被判断为 'object'.

    /* Object类型 */
    console.log('Object类型: ',typeof {});
    // -> Object类型: object
    
    /* null类型 */
    console.log('null类型: ', typeof null);
    // -> null类型: object
    
    /* Array类型 */
    console.log('Array类型: ',typeof []);
    // -> Array类型: object
    
    /* Set类型 */
    console.log('Set类型: ',typeof new Set());
    // -> Set类型: object
    
    /* Date类型 */
    console.log('Date类型: ',typeof new Date());
    // -> Date类型: object

    3. Array.isArray() 的原理 - Object.prototype.toString.call()

    除了 typeof , js 中的某些类型还为我们提供了一些静态方法用于检测特定类型, 比如 Array.isArray() 这个静态方法可以检测传入的参数是否是一个数字, 那么这是基于什么原呢?

    Object 的原型上有一个 toString() 方法: Object.prototype.toString(). Object.prototype.toString() 返回 "[object Type]", 这里的 Type 是对象的类型.

    如果直接调用 Object.prototype.toString(), 则会输出 "[object Object]".

    console.log( Object.prototype.toString() );
    // -> [object Object]

    那么我们该如何使用 Object.prototype.toString() 来判断引用类型的类型呢? 我们可以通过 Function.prototype.call() 改变这个方法的 this 指向, 让其指向我们需要判断的值的类型, 就可以判断引用类型的类型了.

    比如如果将 Object.prototype.toString()this 指向一个数组, 那么就会输出 "[object Array]".

    console.log( Object.prototype.toString.call( [] ) );
    // -> [object Array]

    基于这一点, 那么我们就自己可以实现 Array.isArray():

    function isArray(value) {
        return Object.prototype.toString.call(value) === '[object Array]';
    }

    再拓展一点, 像是 isMap(), isMath() 这些类似的类型判断函数, 也是同样的实现原理:

    function isMap(value) {
        return Object.prototype.toString.call(value) === '[object Map]';
    }
    function isMath(value) {
        return Object.prototype.toString.call(value) === '[object Math]';
    }

    4. 通用的类型判断函数

    在第三节中, 我们了解到了如何判断一个值的类型, 那么其实我们可以基于 Object.prototype.toString() 会返回 "[object Type]" 的原理, 写一个通用的类型判断函数, 获取其中的这个 Type .

    /**
     * 判断 value 的类型是否是给定的 type
     *
     * @param {string} type - 预期想要的类型.
     * @param {any} value - 需要判断的值.
     * @returns {boolean} - 如果传入的 value 是需要的类型, 则输出 true, 否则输出 false
     */
    function judgeType( type, value ) {
        return Object.prototype.toString.call( value ).slice( 8, -1 ).toLowerCase() === type.toLowerCase();
    }

    基于这个通用函数, 我们可以很方便地再次封装具体的类型判断函数:

    const isArray = judgeType.bind( null, 'array' );
    const isSet = judgeType.bind( null, 'set' );
    const isMap = judgeType.bind( null, 'map' );
    const isMath = judgeType.bind( null, 'math' );
    const isDate = judgeType.bind( null, 'date' );

    5. 自定义类判断类型

    如果我们自己定义了一个类, 直接使用 Object.prototype.toString.call() 只会输出 [object Object]:

    class Type {}
    
    console.log( Object.prototype.toString.call( new Type() ) );
    // -> [object Object]

    这里需要定义一个类属性 Symbol.toStringTag , Object.prototype.toString() 获取值类型的本质就是就是获取这个属性的值.

    class Type {
        [Symbol.toStringTag] = 'Type';
    }
    
    console.log( Object.prototype.toString.call( new Type() ) );
    // -> [object Type]

    同理, 由于 Object.prototype.toString() 获取的是 Symbol.toStringTag 的值, 所以原生的一些类型的值也是可能更改的:

    Array.prototype[Symbol.toStringTag] = 'NotArray';
    
    console.log( Object.prototype.toString.call( [ 1, 2, 3 ] ) );
    // -> [object NotArray]
  • TA的每日心情
    慵懒
    1 小时前
  • 签到天数: 822 天

    [LV.10]以坛为家III

    31

    主题

    553

    回帖

    1564

    积分

    荣誉开发者

    积分
    1564

    荣誉开发者新人进步奖油中2周年生态建设者新人报道挑战者 lv2油中3周年喜迎中秋

    发表于 2023-9-30 12:11:04 | 显示全部楼层

    image.png
    typeof function\arrow function\class 都会返回function

    另外typeof 永远不会返回'null'

    回复

    使用道具 举报

  • TA的每日心情
    难过
    2024-4-24 18:57
  • 签到天数: 13 天

    [LV.3]偶尔看看II

    24

    主题

    31

    回帖

    281

    积分

    荣誉开发者

    积分
    281

    荣誉开发者油中2周年生态建设者喜迎中秋

    发表于 2023-9-30 14:09:31 | 显示全部楼层
    steven026 发表于 2023-9-30 12:11
    [md]![image.png](data/attachment/forum/202309/30/120922o4znlbuuaoci6tol.png)
    typeof  function\arrow  ...

    写漏了, 我改一下(
    回复

    使用道具 举报

    发表回复

    本版积分规则

    快速回复 返回顶部 返回列表