解密JavaScript:为什么 [] == ![] 和 a.x = a = {n:2} 让人困惑?

221 阅读3分钟

[] == ![] 为什么是 true

  • 如果等号两边类型相同

    • 对象: 仅当两边的操作数引用同一个对象时返回 true
    const obj = { a: 1 };
    
    obj == obj; // true
    obj == { a: 1 }; // false
    
    • 字符串:仅当两个操作数具有相同的字符且顺序相同时返回 true
    "abc" == "abc"; // true
    "abc" == "cba"; // false
    
    • 数字:如果两个操作数的值相同,则返回 true+0-0 被视为相同的值。如果任何一个操作数是 NaN,返回 false;所以,NaN 永远不等于 NaN
    9 == 9; // true
    +0 == -0; // true
    9 == NaN; // false
    NaN == NaN; // false
    
    • 布尔:仅当操作数都为 true 或都为 false 时返回 true
    true == true; // true
    false == false; // true
    true == false; // false
    
    • 符号:仅当两个操作数引用相同的符号时返回 true
    const symbol = Symbol("key");
    symbol == symbol; // true
    symbol == Symbol("key"); // false
    
    • 大整数:仅当两个操作数的值相同时返回 true
  • 如果等于一边存在 undefinednull,那么另一边 一定也要是undefinednull,否则为false

undefined == undefined; // true
null == null; // true
undefined == null; // true

null == 9; // false
null == "9"; // false
  • 如果等号两边存在一边对象,一边原始值

将对象转换为原始值 (隐式类型转换)

  • 如果等号两边都是原始
    • 如果类型相同 则参考类型相同比较
    • 如果其中一个操作数是符号(Symbol)而另一个不是,返回 false
    • 如果其中一个布尔,另一个不是布尔,将布尔值转换成数字
      • true -> 1
      • false -> 0
    • 如果其中一个数字,另一个是字符串,将字符串转换为数字
      • '12.34' -> 12.34
      • '12.a34' -> NaN

总结

回归正题

[] == ![]

第一步 显式类型转换
![] = false
原式 = [] == false

第二步 进入 第三条比较规则
将对象转换为原始值
[] = ''
原式 = '' == false

第三步 进入 第四条比较规则
布尔转换成数字
原式 = '' == 0

第四步 进入 第四条比较规则
字符串换成数字
原式 = 0 == 0

第五步 进入 第一条比较规则
两边类型相等 且都为数字 且 没有NaN 且 操作数相等
则 返回 true

连等赋值 a.x = a = {n:2}

var a = { n: 1 };
var b = a;
a.x = a = { n: 2 };
console.log(a.x);
console.log(b.x);
console.log(a);
console.log(b);
// 打印什么

需要了解的前置知识 运算符优先级

图解

  • var a = { n: 1 } 给a在堆中开辟了一块内存空间

image.png

  • var b = a 将b的指针指向了堆内存中与 a 相同的内存空间 image.png
  • a.x = a = { n: 2 } 优先级.最高 优先执行 a.x image.png
  • 赋值操作 从右 到左执行 a = {n: 2} a指向一块新的内存空间 image.png
  • 最后 执行 a.x = {n: 2} a.x即 b.x image.png

搞一个简称

地址1: {n: 1, x: 箭头}

地址2: {n: 2}

a 现在指向的是 地址2

b 现在指向的是 地址1

a.x 因为地址2中没有x 所以是 undefined

b.x 指向地址2

结尾

草率结尾