参考自 微信公众号 鱼头的 Web 海洋
关于这道题目:
var a = ?;
if (a == 1 && b == 2 && c == 3) {console.log('yes');
}
学习了网上的几种解法, 如下:
首先,JS 中类型转化只有三种情况:
- 转换为布尔值
- 转换为数字
- 转换为字符串
对象在转换类型的时候, 会执行原生方法 ToPrimitive
其算法如下:
1. 如果已经是 原始类型 , 则返回当前值;
2. 如果需要转 字符串 则先调用 toString 方法, 如果此时是 原始类型 则直接返回, 否则再调用 valueOf 方法并返回结果;
3. 如果不是 字符串 , 则先调用 valueOf 方法, 如果此时是 原始类型 则直接返回, 否则再调用 toString 方法并返回结果;
4. 如果都没有 原始类型 返回, 则跑出 T ypeErro r 类型错误.
解法如下:
1.
var a = {arr: [3, 2, 1],
valueOf () {console.group('valueOf');
console.log(this.arr);
console.groupEnd('valueOf');
return this.arr.pop();}
}
if (a == 1 && a == 2 && a == 3) {console.log('yes');
}
执行结果:
解析:
1.运行时会先判断 a 的类型, 此时 typeof a === ‘object’, 不是原始类型, 也不是字符串, 因此会先执行 a.valueOf()
2.由于 valueOf()被覆盖了, 因此执行覆盖后的 valueOf(), 每一次都会返回 a.arr 的尾元素, 并更新 a.arr
3.得出三次执行结果为 1, 2, 3, 实现了这个功能
2.
var b = {arr: [3, 2, 1],
toString () {console.group('toString');
console.log(this.arr);
console.groupEnd('toString');
return this.arr.pop();}
}
if (b == 1 && b == 2 && b == 3) {console.log('yes');
}
执行结果:
解析:
1.运行时会先判断 b 的类型, 此时 typeof a === ‘object’, 不是原始类型, 也不是字符串, 因此会先执行 b.valueOf()
2.b.valueOf()得到的结果是 {arr: Array(3), toString: ƒ}, 不是原始类型. 不是字符串, 因此执行 b.toString()
3.由于 toString()被覆盖了, 因此执行覆盖后的 toString(), 每一次都会返回 b.arr 的尾元素, 并更新 b.arr
3.得出三次执行结果为 1, 2, 3, 实现了这个功能
3.
var c = {arr: [3, 2, 1],
[Symbol.toPrimitive] () {console.group('Symbol.toPrimitive');
console.log(this.arr);
console.group('Symbol.toPrimitive');
return this.arr.pop();}
}
if (c == 1 && c == 2 && c == 3) {console.log('yes');
}
执行结果:
解析:
先把上面的方法合并, 测试优先级:
var d = {arr: [3, 2, 1],
valueOf () {console.group('valueOf');
console.log(this.arr);
console.groupEnd('valueOf');
return this.arr.pop();},
toString () {console.group('toString');
console.log(this.arr);
console.groupEnd('toString');
return this.arr.pop();},
[Symbol.toPrimitive] () {console.group('Symbol.toPrimitive');
console.log(this.arr);
console.group('Symbol.toPrimitive');
return this.arr.pop();}
}
if (d == 1 && d == 2 && d == 3) {console.log('yes');
}
执行结果:
可以看出会先执行 toPrimitive 这个原生方法, 但是被覆盖了, 所以执行覆盖后的 toPrimitive()
4.
var f = {
reg: /\d/g,
valueOf() { return this.reg.exec(123)[0] }
}
if (f == 1 && f == 2 && f == 3) {console.log('yes');
}
执行结果:
解析:
1.exec() 方法在一个指定字符串中执行一个搜索匹配。返回一个结果数组或 null。
2.如果匹配成功,exec() 方法返回一个数组,并更新正则表达式对象的属性。返回的数组将完全匹配成功的文本作为第一项,将正则括号里匹配成功的作为数组填充到后面。如果匹配失败,exec() 方法返回 null。
3.先测试 var reg=/d/g; reg.exec(123); 得到以下结果:
可看到正则进行全局搜索, 判断返回一个数据, 数组的首元素为成功匹配的文本
4. 因此每次进行 f == 1, f == 2, f == 3 时都会返回数组的首元素, 也就是匹配的文本. 由此实现这个功能