思考题 - == 等于操作符

317 阅读3分钟

题目

问: 变量 a 在等于什么的情况下,能是 if 语句的条件成立,控制台能输出 'OK'。

var a = ?;
if (a == 1 && a == 2 && a == 3) {
    console.log('OK');
}

解题思路

根据题意 == 等于操作符右边的操作数是数值。

如果只是 number 类型数值的进行比较,显然是无法满足条件的。

而 == 等于操作符在比较两个操作数时,如果两个操作数的数据类型不同,那么会先进行(强制)数据类型转换,再比较两个操作数是否相等。

那么如果 a 是一个可以转换为数值的值,就有可能使条件成立。

按照把其他数据类型的值转换成 Number 类型的 Number() 、parseInt() 和 parseFloat() 三个函数,只有 Number() 可以转换任何数据类型的值。

又按照 Number() 的转换规则,可以排除 a 是原始值类型, 因为无法让一个原始值与3个数值相等,所以只能是对象类型的值。

方案1:假设 a 是个对象

根据把对象转换为数字的规则,给 a 的 Symbol.toPrimitive 属性(方法)重新定义一个函数,可以改变其默认返回值。

具体代码如下:

var a = {
    i: 0
};
// 给 a 的 Symbol.toPrimitive 属性,重新定义一个函数
a[Symbol.toPrimitive] = function toPrimitive() {
    return ++this.i; // this -> a
};
if (a == 1 && a == 2 && a == 3) {
    console.log('OK');
}

每执行一次 == 等于比较,就会触发一次强制转换,从而会调用一次Symbol.toPrimitive 属性(方法)并返回 a.i 累加 1 的值, 所以每次强制转换的返回值都是不一样的,是累加的。

方案2:假设 a 是个数组

根据把对象转换为数字的规则,我们可以改写数组实例的 toString() 指向,具体代码如下:

var a = [1, 2, 3];
a.toString = a.shift;
if (a == 1 && a == 2 && a == 3) {
    console.log('OK');
}

借用数组的 shift() 方法,其功能是:删除数组的第一个元素,并返回被删除元素。

知识点

1. == 在转换操作数类型时遵循的规则

(1)如果任一操作数是布尔值,则将其转换为数值再比较是否相等。false 转换为 0,true 转换为 1。

(2)如果一个操作数是字符串,另一个操作数是数值,则尝试将字符串转换为数值,再比较是否相等。

(3)如果一个操作数是对象,另一个操作数不是,则调用对象的 valueOf() 方法取得其原始值,再根据前面的规则进行比较。

2. == 在进行比较时遵循的规则

(1)null 和 undefined 相等。

(2)null 和 undefined 不能转换为其他类型的值再进行比较。也就是说 null 和 undefined 同其他任何值都不相等。

(3)NaN 同任何值都不相等,包括它自己。

(4)如果两个操作数都是对象,则比较它们是不是同一个对象。即比较它们存储的堆内存地址是否相同。

关联笔记

以上内容,属于个人学习笔记整理,如有不对请指正。