[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)

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

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'

加号的运算规则

摘自: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

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值