相等,还是不等(4)

Updated: 2019-01-06

入门

在连续对多个相等条件进行判断的时候,可以用and(&&),or(||)来连接,但并不是所有的条件都会被检查,比如&&在遇到第一个False的时候,无论后面的真假,可以直接返回False;同样的||在遇到第一个True的时候整个语句的真假已定。

坑!

这个坑源自这篇文章:什么时候a==1 && a==2 && a==3?

var aᅠ = 1;
var a = 2;
var ᅠa = 3;
if (aᅠ == 1 && a == 2 && ᅠa == 3) {
  console.log("Whaaaaa?");
}

进阶

方法1

谜底揭开的时候,我的第一感觉是,这好无聊...实际上三个a并不是同一个变量,这里用到了一个不可见的韩语的 Unicode 字符U+FFA0,叫做 Halfwidth Hangul Filler,第一个变量是a后面加上那个字符,而第三个是a之前加上那个字符,由于不可见,所以看起来好像是同一个a。可以把它转换为十六进制看看:

> "ᅠa".charCodeAt(0).toString(16)
'ffa0'

正是U+FFA0

方法2

有趣的是评论中提供了另一种方法满足a==1 && a==2 && a==3而不需要不可见字符:

const a = {
  valueOf: (function() {
    let x = 1;
    return () => x++;
  })()
};

console.log(a == 1 && a == 2 && a == 3); // => true

在Javascript中,任何一个object都有valueOf()这个方法(类似于toString()),这个object在计算中会用valueOf()来产生一个值:

> b = {valueOf: () => 10}
{ valueOf: [Function: valueOf] }

直接打印出b并不会看到10:

> b
{ valueOf: [Function: valueOf] }

但放在计算中则会现原形:

> b == 10
true
> b == 1
false
> b + 20
30

方法3

方法2如果用===则返回的是false

console.log(a === 1 && a === 2 && a === 3); // => false

因为虽然计算b的值的时候返回的是10,它的类型依然是object:

> typeof(b)
'object'

这是一种满足===的方法:

let i = 0;
Object.defineProperty(global, "a", {
  get: function() {
    return ++i;
  }
});
console.log(a === 1 && a === 2 && a === 3); // => true

如果不是在node而是在浏览器中运行需要将global换成window。这两个特殊的全局object的property可以直接使用。而且作为property,a的类型跟它的返回值相同为number

> typeof(a)
'number'