本文旨在总结 JavaScript数据类型转换方面的知识点
- toString转换的结果
- valueOf转换的结果
- 隐式转换/显示转换
- 转换机制
- 实战操作
一.Object原型有toString,子类型对toString有重写,示例:
talk is cheap show me your code!!!
1.Object.prototype.toString.call()
Object.prototype.toString.call(false) // [object Boolean]
Object.prototype.toString.call(123) // [object Number]
Object.prototype.toString.call('abc') // [object String]
Object.prototype.toString.call({}) // [object Object]
Object.prototype.toString.call([]) // [object Array]
Object.prototype.toString.call(new Date()) // [object Date]
Object.prototype.toString.call(new RegExp(/[a-b]/)) // [object RegExp]
Object.prototype.toString.call(undefined) // [object Undefined]
Object.prototype.toString.call() // [object Undefined]
Object.prototype.toString.call(null) // [object Null]
2.Array.prototype.toString.call()
Array的重写有两点不同,首先是数组类型返回 '1,2,3' 格式的字符串,其次是传入undefined和null会报错异常,传入其他类型与 Object一致
Array.prototype.toString.call(false) // [object Boolean]
Array.prototype.toString.call(123) // [object Number]
Array.prototype.toString.call('abc') // [object String]
Array.prototype.toString.call({}) // [object Object]
Array.prototype.toString.call([1,2,3]) // *** '1,2,3'
Array.prototype.toString.call(new Date()) // [object Date]
Array.prototype.toString.call(new RegExp(/[a-b]/)) // [object RegExp]
Array.prototype.toString.call(undefined) // *** error
Array.prototype.toString.call() // *** error
Array.prototype.toString.call(null) // *** error
除Array和Object类型外,其余类型不能用在非自身子类型的变量上,否则报错异常
3.包装类型:Number.prototype.toString.call()
Number.prototype.toString.call() // *** error
Number.prototype.toString.call(123) // 123
4.包装类型:String.prototype.toString.call()
String.prototype.toString.call() // *** error
String.prototype.toString.call('123') // '123'
5.Date.prototype.toString.call()
Date.prototype.toString.call() // *** error
Date.prototype.toString.call(new Date()) // 'Sun Sep 11 2022 05:59:39 GMT+0800 (中国标准时间)'
6.RegExp.prototype.toString.call()
RegExp.prototype.toString.call() // *** error
RegExp.prototype.toString.call(new RegExp(/[a-z]/)) // '/[a-z]/'
7.Function.prototype.toString.call()
Function.prototype.toString.call() // *** error
Function.prototype.toString.call(function() {}) // 'function() {}'
二.toString.call()等同Object.prototype.toString.call()
toString.call(false) // [object Boolean]
toString.call(123) // [object Number]
toString.call('abc') // [object String]
toString.call({}) // [object Object]
toString.call([]) // [object Array]
toString.call(new Date()) // [object Date]
toString.call(new RegExp(/[a-b]/)) // [object RegExp]
toString.call(undefined) // [object Undefined]
toString.call() // [object Undefined]
toString.call(null) // [object Null]
三.隐式转换&&运算符
// 基本类型在操作属性或调用方法时,会隐式用包装类处理,操作之后删除包装类
let a = 1
a.len = 4
console.log(a.len) // undefined
// 运算时根据[Symbol.toPrimitive]判断先调用valueOf再调用toString,还是先调用toString,再调用valueOf
console.log(new Date()+',hello') // Sun Sep 11 2022 05:59:39 GMT+0800 (中国标准时间),hello
console.log(new Date()-10) // 1662867529712
console.log([2,3,4]+',hello') // 2,3,4,hello
console.log({} > 1) // false
console.log(['a'] == 'a') // true
四.valueOf
直接调用
(false).valueOf() // false
(123).valueOf() // 123
('abc').valueOf() // 'abc'
({}).valueOf() // {}
([]).valueOf() // []
(new Date()).valueOf() // 1662878551856
(new RegExp(/[a-b]/)).valueOf() // /[a-b]/
(undefined).valueOf() // error
valueOf() // error
(null).valueOf() // error
Object.valueOf返回的是对象
Object.prototype.valueOf.call(false) // [Boolean: false]
Object.prototype.valueOf.call(123) // [Number: 123]
Object.prototype.valueOf.call('abc') // [String: 'abc']
Object.prototype.valueOf.call({}) // {}
Object.prototype.valueOf.call([]) // []
Object.prototype.valueOf.call(new Date()) // 2022-09-11T03:45:44.314Z
Object.prototype.valueOf.call(new RegExp(/[a-b]/)) // /[a-b]/
Object.prototype.valueOf.call(undefined) // error
Object.prototype.valueOf.call() // error
Object.prototype.valueOf.call(null) // error
五.显示转换
String
// 调用变量自身类型toString->Object原型上toString->valueOf
console.log(String({name:1})) // [object Object]
Number
console.log(Number([1,2])) // NaN
六.[Symbol.toPrimitive]
MDN:Symbol.toPrimitive 是一个内置的 Symbol 值,它是作为对象的函数值属性存在的,当一个对象转换为对应的原始值时,会调用此函数
引用类型转换时先会调用symbol.toPrimitive方法,参数hint会得到三种不同情况:'string','number','default'判断先调用toString还是valueOf
Array.prototype[Symbol.toPrimitive] = function(hint) {
if(hint == 'string') {
return this.toString() instanceof Object ? : this.valueOf() : this.toString()
}else {
return this.valueOf() instanceof Object ? : this.toString() : this.valueOf()
}
}
Array.prototype.toString = function(hint) {
console.log('toString')
return this.join(',')
}
Array.prototype.valueOf = function(hint) {
console.log('valueOf')
return this
}
a=[1,2]
// hint == ‘string'情况
console.log(`${a}`)
console.log(String(a))
// hint == ‘default'情况,无法确定是string还是number时是default
console.log(a+123)
console.log(a==132)
// hint == ‘number'情况
console.log(+a)
console.log(a-1)
console.log(a>1)
console.log(a*1)
hint==string则会优先调用toString转换,如果返回的是引用数据类型则继续调用valueof
hint==default||hint==number则会优先调用valueOf转换,如果返回的是引用数据类型则继续调用toString
七.实战
1)进制转换,生成随机验证码
// 生成随机数,按照36(26字母+10数字)进制转换成字符串,截取字符串
Math.random().toString(36).slice(3,7)
2)实现累加函数
let arr = []
function add(...args){
arr = arr.concat(args)
return add
}
add.toString = function(){
return arr.reduce((a,b)=>a+b,0)
}
console.log(+add(1,2)(3)) // 6
3)实现a==1&&a==2&&a==3
let value = 1
class A {
[Symbol.toPrimitive](){
return value++
}
}
let a = new A()
console.log(a==1&&a==2&&a==3) // true