数据转换两种方式,隐式转换和显式转换。
字符串拼接
console.log(10 + '10')
// '1010'
数学运算(+ - * /...)
console.log(+'10')
// 10
console.log(10 - '10')
// 0
==比较
console.log(10=='10')
// true
console.log(10==='10')
// false
显示转换
Number('10')
// 10
String(10)
// '10'
对象转换为数字/字符串经历了哪些步骤(底层机制)
- 首先检测对象的 Symbol.toPrimitive 这个属性,获取其原始值
- 如果没有这个属性,则继续调用它的
valueOf
,也是获取原始值 - 如果值不是原始值,则继续调用
toString
转换为字符串 - 再把字符串转使用
Number
换为数字
let obj = {name:10}
obj - 10 = NaN
1. obj[Symbol.toPrimitive]
// undefined
2. obj.valueOf()
// {0: 10}
3. obj.toString()
// '[object Object]'
4. Number('[object Object]')
// NaN
5. NaN-10
// NaN
那为什么 new Number(10) 也是对象,结果却不一样呢?我们来看一下
typeof new Number(10)
// 'object'
let n = new Number(10)
n - 5 = 5
1. n[Symbol.toPrimitive]
// undefined
2. n.valueOf()
// 10
// 10 - 5 =5
让我们来练习一下,改造一下第一个对象
let obj = {
name: 10,
[Symbol.toPrimitive]() {
return 10
}
}
console.log(obj - 10)
// 0
看一道阿里的面试题,是不是觉得就超级简单了,当初这道题的正确率可是很低的,通过率可能1%都不到
var a = ?;
if (a == 1 && a == 2 && a == 3) {
console.log('OK');
}
知道了对象转数字的步骤我们就可以来做了,这边提供两类解题思路,第一类隐式进行数据类型转换来进行处理,就是上面我们看到对象转换数字的步骤,我们至少能用三种方法;如果算上数组转数字的话也至少能再用三种方法;第二类,就是我们的数据劫持,也是起码两种方法。我们来试一试吧
第一种方法,给对象添加 Symbol.toPrimitive
var a = {
n: 1,
[Symbol.toPrimitive]() {
return this.n++
}
};
if (a == 1 && a == 2 && a == 3) {
console.log('OK');
}
第二种方法,给对象添加 valueOf
var a = {
n: 1,
valueOf() {
return this.n++
}
};
if (a == 1 && a == 2 && a == 3) {
console.log('OK');
}
第三种方法,给对象添加 toString
var a = {
n: 1,
toString() {
return this.n++
}
};
if (a == 1 && a == 2 && a == 3) {
console.log('OK');
}
数组的第一种方法...
var a = [1,2,3]
a.toString = a.shift
if (a == 1 && a == 2 && a == 3) {
console.log('OK');
}
第四种方法,使用ES5的 Object.defineProperty
var a = {
n: 1,
toString() {
return this.n++
}
};
if (a == 1 && a == 2 && a == 3) {
console.log('OK');
}
第五种方法,使用ES6的 proxy
var a = {
n: 1,
toString() {
return this.n++
}
};
if (a == 1 && a == 2 && a == 3) {
console.log('OK');
}
补充一个知识点
Symbol.toPrimitive
在 Symbol.toPrimitive 属性(用作函数值)的帮助下,一个对象可被转换为原始值。该函数被调用时,会被传递一个字符串参数 hint ,表示要转换到的原始值的预期类型。 hint 参数的取值是 "number"、"string" 和 "default" 中的任意一个。
// 一个没有提供 Symbol.toPrimitive 属性的对象,参与运算时的输出结果
var obj1 = {};
console.log(+obj1); // NaN
console.log(`${obj1}`); // "[object Object]"
console.log(obj1 + ""); // "[object Object]"
// 接下面声明一个对象,手动赋予了 Symbol.toPrimitive 属性,再来查看输出结果
var obj2 = {
[Symbol.toPrimitive](hint) {
if (hint == "number") {
return 10;
}
if (hint == "string") {
return "hello";
}
return true;
}
};
console.log(+obj2); // 10 -- hint 参数值是 "number"
console.log(`${obj2}`); // "hello" -- hint 参数值是 "string"
console.log(obj2 + ""); // "true" -- hint 参数值是 "default"
网友评论