• [JS]数据类型转换规则和运算


    参考:https://github.com/mqyqingfeng/Blog/issues/159

    类型转换

    先总结
    valueOftoString 的调用顺序和返回值,如果返回值为原始值则使用,如果两个函数都没返回原始值,则报错

    valueOftoString 方法的调用顺序在这两个方法都返回原始值的时候有用,因为先被调用的那个方法的返回值会作为运算的值。

    // 每个对象都有 toString 和 valueOf 方法,其中
    // toString 尝试返回对象的字符串表示
    // valueOf 尝试返回对象的数字表示
    // 这两个方法都有可能返回原始类型的值,但也有可能返回对象本身(非原始类型)
    // 要执行运算时,会根据运算规则调用 toString 或者 valueOf 方法,但是需要注意的是调用的方法会返回原始类型的值
    // 例子
    
    // hook obj toString and valueOf
    // 因为放到浏览器环境里测试不加 test 属性会导致非测试代码的 toString 被调用输出
    // 所以要加个 test 属性以区分代码来源
    const ots = Object.prototype.toString
    Object.prototype.toString = function () {
        if (this.test) {
            console.log('To String called')
        }
        return ots.call(this)
    }
    
    const vo = Object.prototype.valueOf
    Object.prototype.valueOf = function () {
        if (this.test) {
            console.log('ValueOf String called')
        }
        return vo.call(this)
    }
    
    
    // 运行结果:
    // Number({ test: 1 })
    // ValueOf String called
    // To String called
    // NaN
    
    // 可以看到 Number 方法先调用了 valueOf,但是 valueOf 没有返回原始值,故调用了 toString
    // 得到结果 NaN
    Number({})
    
    // 运行结果
    // ValueOf String called
    // 0
    
    // 同样先调用 valueOf,发现返回值为 0,所以直接用 0 作为输入
    const a = []
    undefined
    a.test = 1
    Number(a)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46

    [] + {}、({}) + [] 等奇怪的加法运算

    a = {
        valueOf() {
            return 10
        },
        toString() {
            return 0
        }
    }
    
    b = []
    b.valueOf = function() {
      return 50
    }
    
    b.toString = function() {
      return 100
    }
    
    
    // Number 先调用 valueOf,故返回值为 10
    Number(a)
    // 同理,先调用 toString,返回值为 '0'
    String(a)
    
    // 同理
    Number(b)
    String(b)
    
    // 20
    a + a
    
    // 100
    b + b
    
    // 110
    a + b + b
    
    // 120
    a + 100
    
    // '10a'
    a + 'a'
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42

    加号的运算规则

    摘自:https://github.com/mqyqingfeng/Blog/issues/159

    • 将 + 号两边的变量转为原型类型,对于对象类型的变量,会先调用 valueOf 方法,如果是原始类型就返回;
    • 如果不是原始类型就调用 toString 方法。也就是上面的 ToPrimitive 方法
    • 如果+号两侧有一个 string 类型,将另一个也转为 string 类型进行字符串拼接
    • 否则按照 number 类型计算(转成元素类型后为 number ,且另一个运算数也是 number

    回头看上面的代码,因为 a + a 是两个对象相加,所以会先调用 valueOf 方法,同理 a + 10 因为 a 被转为 number,所以整体也是 number 运算。
    a + '0' 则是因为有 string 参与运算,将 a.valueOf 的结果当成 string 看待,得到 ‘100’

    加号运算规则重点再总结

    上面摘自别人的总结,下面用自己的语言总结下

    如果加号遇到对象类型,会先调用该对象的 valueOf 看结果是不是原始类型,如果不是继续调用 toString 方法,都不是原始类型则报错,得到原始类型后看另一个运算数是什么类型,为 string 则整体 string(当然如果自己得到的元素类型为 string,整体也是 string),否则进行 number 运算。

    toString 和 valueOf 返回的都不是原始类型运算结果示例:

    o = {
    	valueOf(){
    		return {}
    	}, 
    	toString(){
    		return {}
    	}
    }
    
    // 报错
    // VM703:1 Uncaught TypeError: Cannot convert object to primitive value
    o + 10
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    可以看出 toString 和 valueOf 的值是 JS 进行运算最终落实到的值,这样就能解释这章标题执行运算时得到的一些奇怪结果的原因了。

  • 相关阅读:
    自底向上语法分析(bottom-up parsing)
    centos7 装机遇到的问题
    [附源码]Java计算机毕业设计SSM仿咸鱼二手物品交易系统
    技术 | 终端安全 | 服务器并不像您想象的那么安全
    概率论的学习和整理13--方差和协方差(未完成)
    uniapp:如何实现点击图片可以全屏展示预览
    k8s快速入门教程-----4 工作负载控制器之deployment
    分布式系统第五讲:分布式事务及实现方案
    离线win7上用anaconda离线创建虚拟环境
    华为设备配置RSVP认证
  • 原文地址:https://blog.csdn.net/qq_39559879/article/details/125620520