JavaScript中如何让 x == 1 && x == 2 && x == 3 等式成立

作者:拾光时间:2026-10-25 15:16:40浏览:317

本文探讨JavaScript中x == 1 && x == 2 && x == 3成立的原理。通过重写对象的valueOf或toString方法,利用宽松相等==的隐式类型转换机制,使每次比较时动态返回递增的值,从而满足等式条件。

前言

在一次面试中,面试官突然提出一个问题:如何让变量 x 同时满足 x 等于 1、x 等于 2 以及 x 等于 3 的等式条件?

听到这个问题,笔者当时感到十分困惑,甚至觉得题目有些不可思议。

虽然当时未能立即给出答案,但觉得这个题目非常有趣,因此在此分享后续的解题思路。

在JavaScript中,宽松相等(==)和严格相等(===)都用于判断两个值是否“相等”。首先需要明确题目中的“等于”具体指哪一种,下面分析两者的区别。

(1)对于基础类型之间的比较,== 和 === 存在区别:

  • (1.1)当比较不同类型时,== 会将值转换为同一类型后比较“值”是否相等,而 === 如果类型不同,结果直接为不等。
  • (1.2)当比较同类型时,两者都直接进行“值”比较,结果一致。

(2)对于引用类型之间的比较,== 和 === 没有区别,均进行“指针地址”比较。

(3)基础类型与引用类型之间的比较,== 和 === 存在区别:

  • (3.1)对于 ==,会将引用类型转换为基础类型,然后进行“值”比较。
  • (3.2)因为类型不同,=== 的结果为 false。

“== 允许在相等比较中进行强制类型转换,而 === 不允许。”

由此可见,题目中的“等于”指的是宽松相等 ==,因此问题转化为:如何让 x == 1 && x == 2 && x == 3 成立。

那么,多种数据类型之间的相等比较有哪些规则呢?笔者查阅了相关资料,整理如下。

同类型数据之间的相等比较

  • 如果 Type(x) 等于 Type(y),ES5 规范 11.9.3.1 定义如下:
  • 如果 Type(x) 是 Undefined,返回 true。
  • 如果 Type(x) 是 Null,返回 true。
    • 如果 Type(x) 是 Number ,则
    • 如果 x 是 NaN,返回 false。
    • 如果 y 是 NaN,返回 false。
    • 如果 x 与 y 的数字值相同,返回 true。
    • 如果 x 为 +0,y 为 -0,返回 true。
    • 如果 x 为 -0,y 为 +0,返回 true。
  • 如果 Type(x) 是 String,则如果 x 和 y 是字符的序列完全相同(相同的长度和相同位置相同的字符),则返回 true。否则,返回 false。
  • 如果 Type(x) 是 Boolean,则如果 x 和 y 都为 true 或都为 false,则返回 true。否则,返回 false。
  • 如果 x 和 y 指向同一对象,则返回 true。否则,返回 false。

null 和 undefined 之间的相等比较

null 和 undefined 之间的 == 也涉及隐式强制类型转换。ES5 规范 11.9.3.2-3 定义如下:

  • 如果 x 为 null,y 为 undefined,则结果为 true。
  • 如果 x 为 undefined,y 为 null,则结果为 true。

在 == 中,null 和 undefined 相等(它们也与其自身相等),除此之外其他值都不和它们两个相等。

这也就是说,在 == 中null 和 undefined 是一回事。

var a = null;
var  b; 
a == b; // true
a == null; // true
b == null; // true
a == false; // false
b == false; // false
a == ""; // false
b == ""; // false
a == 0; // false
b == 0; // false

字符串和数字之间的相等比较

ES5 规范 11.9.3.4-5 定义如下:

  • 如果 Type(x) 是数字,Type(y) 是字符串,则返回 x == ToNumber(y) 的结果。
  • 如果 Type(x) 是字符串,Type(y) 是数字,则返回 ToNumber(x) == y 的结果。
var a = 42;

var b = "42";

a === b; // false

a == b; // true
复制代码

因为没有强制类型转换,所以 a === b 为 false,42 和 "42" 不相等。

根据规范,"42" 应该被强制类型转换为数字以便进行相等比较。

其他类型和布尔类型之间的相等比较

ES5 规范 11.9.3.6-7 定义如下:

  • 如果 Type(x) 是布尔类型,则返回 ToNumber(x) == y 的结果;
  • 如果 Type(y) 是布尔类型,则返回 x == ToNumber(y) 的结果。

仔细分析例子,首先:

var x = true;
var y = "42";
x == y; // false

Type(x) 是布尔值,所以 ToNumber(x) 将 true 强制类型转换为 1,变成 1 == "42",二者的类型仍然不同,"42" 根据规则被强制类型转换为 42,最后变成 1 == 42,结果为 false。

对象和非对象之间的相等比较

关于对象(对象 / 函数 / 数组)和标量基本类型(字符串 / 数字 / 布尔值)之间的相等比较,ES5 规范 11.9.3.8-9 做如下规定:

  • 如果 Type(x) 是字符串或数字,Type(y) 是对象,则返回 x == ToPrimitive(y) 的结果;
  • 如果 Type(x) 是对象,Type(y) 是字符串或数字,则返回 ToPromitive(x) == y 的结果。

什么是 toPrimitive() 函数?

**应用场景:**在 JavaScript 中,如果想要将对象转换成基本类型时,再从基本类型转换为对应的 String 或者 Number,实质就是调用 valueOf 和 toString 方法,也就是所谓的拆箱转换。

**函数结构:**toPrimitive(input, preferedType?)

参数解释:

input 是输入的值,即要转换的对象,必选;

preferedType 是期望转换的基本类型,他可以是字符串,也可以是数字。选填,默认为 number;

执行过程:

如果转换的类型是 number,会执行以下步骤:

  • 如果 input 是原始值,直接返回这个值;
  • 否则,如果 input 是对象,调用 input.valueOf(),如果结果是原始值,返回结果;
  • 否则,调用input.toString()。如果结果是原始值,返回结果;
  • 否则,抛出错误。 如果转换的类型是 string,2和3会交换执行,即先执行 toString() 方法。

valueOf 和 toString 的优先级:

  • 进行对象转换时 (alert(对象)),优先调用 toString 方法,如没有重写 toString 将调用 valueOf 方法,如果两方法都不没有重写,但按 Object 的 toString 输出。
  • 进行强转字符串类型时将优先调用 toString 方法,强转为数字时优先调用 valueOf。
  • 在有运算操作符的情况下,valueOf 的优先级高于 toString。

由此可知,若 x 为对象时,我们改写 x 的 valueOf 或 toString 方法可以让标题的等式成立:

const x = {
  val: 0,
  valueOf: () => {
    x.val++
    return x.val
  },
}

或者:

const x = {
  val: 0,
  toString: () => {
    x.val++
    return x.val
  },
}

给对象 x 设置一个属性 val 并赋值为 0,并修改其 valueOf、toString 方法,在 “x == 1 && x == 2 && x == 3”判断执行时,每次等式比较都会触发 valueOf、toString 方法,都会执行 val++ ,同时把最新的 val 值用于等式比较,三次等式判断时 val 值分别为 1、2、3 与等式右侧的 1、2、3 相同,从而使等式成立。

前言

到此这篇关于JavaScript中如何让 x == 1 && x == 2 && x == 3 等式成立的文章就介绍到这了,更多相关JS 让 x == 1 && x == 2 && x == 3 成立内容请搜索本站以前的文章或继续浏览下面的相关文章希望大家以后多多支持本站!

作者最新文章