面试题
如何让一个变量 a = = 1 && a = = 2 && a = = 3 结果为 true。
考察点
此题考察的是隐式类型转换。想要变量 a 等于 (==)1/2/3 ,那么变量 a 不可能是基本数据类型。所以只能是引用数据类型。引用数据类型与基本数据类型进行比较时,会隐式地调用 toString 方法,将其转换为基本数据类型。
方法一
数组模式下,重写 toString 方法或者 join 方法。
var a = [1,2,3];
a.toString = a.shift;
console.log(a == 1 && a == 2 && a == 3) //true
var a = [1,2,3];
a.join = a.shift;
console.log(a == 1 && a == 2 && a == 3) //true
方法二
通过 defineProperty 和 Proxy 的 get 方法进行数据劫持。
Object.defineProperty(window, 'a', {
get: function() {
return this.value = this.value ? (++this.value) : 1
}
});
console.log(a == 1 && a == 2 && a == 3) //true
let i = 1;
var a = new Proxy({},{
get:function () {
return ()=>i++
}
})
console.log(a == 1 && a == 2 && a == 3) //true
这里需要注意的是 defineProperty 和 Proxy 的参数区别。defineProperty 的 get 方法在第三个参数对象中,return 的是 value(值)。而 Proxy 的 get 方法在第二个参数对象中,return 的是 function (函数)。
方法三
重写对象的 toString 方法或者 valueOf 方法。
var a = {
num:1,
toString:function () {
return this.num++
}
}
console.log(a == 1 && a == 2 && a == 3) //true
var a = {
num:1,
valueOf:function () {
return this.num++
}
}
console.log(a == 1 && a == 2 && a == 3) //true
方法四
部署 ES6 Symbol 的 toPrimitive 接口。
var a = {
num: 1,
[Symbol.toPrimitive]() {
return this.num++;
}
}
console.log(a == 1 && a == 2 && a == 3) //true
总结
- 数组,重写 toString 方法或者 join 方法。join 方法默认调用 toString 方法。
- 对象,重写 toString 方法或者 valueOf 方法。或者部署 ES6 [Symbol.toPrimitive] 接口。或者通过 defineProperty/Proxy 的 get 方法进行数据劫持。