JavaScript:(a==1 && a==2 && a==3)能输出true么?

若是你能确切的答出能够,那恭喜你,你能够绕道了git

前言

有人会说,这个问题好奇葩,放在别的语言里,这要是能输出true,估计是见鬼了,可是你别说,放在js中好真有可能。最近在一我的的推特上提了一个问题:github

  • 问题:Can (a==1 && a==2 && a==3) ever evaluate to true?
  • 答案:yes

在这篇文章中,我将解释这段代码的原理:windows

const a = {
  num: 0,
  valueOf: function() {
    return this.num += 1
  }
};
const equality = (a==1 && a==2 && a==3);
console.log(equality); // true
复制代码

你能够打开chorme浏览器,而后打开开发者模式,在console中输入这段代码,你就能够看到输出结果([windows]: Ctrl + Shift + J [mac]: Cmd + Opt + J)浏览器

有什么窍门呢?

其实也没有,能有的就是js中的两个概念:函数

  • 隐式转换
  • object的valueOf函数

隐式转换

注意:这题里面咱们用的是==而不是===,在js中==表明的是等于而不是全等,那么就存在变量的隐式转化问题。这就意味着结果会比咱们所指望的更多的可能性。对于js的隐式转化,真的有不少文章,我推荐一下如下几篇博客,若是你想要了解,能够点进去:测试

推荐博客ui

valueOf

JavaScript提供了一种将对象转化为原始值的方法:Object.prototype.valueOf(),默认状况下,返回正在被调用的对象。this

咱们举个例子:lua

const a = {
  num: 0
}
复制代码

咱们能够对上述对象使用valueOf方法,他会返回一个对象。spa

a.valueOf();
// {num: 0}
复制代码

是否是很酷,咱们能够用typeOf来检测一下这个输出结果的类型:

typeof a.valueOf();
// "object"
复制代码

为了让valueOf能够更方便将一个对象转化成原始值,咱们能够重写他,换种说法就是咱们能够经过valueOf来返回一个字符串、数字、布尔值等来代替一个对象,咱们能够看如下代码:

a.valueOf = function() {
  return this.num;
}
复制代码

咱们已经重写了原生的valueOf()方法,当咱们调用valueOf的时候,他会返回a.num。那咱们如今运行如下:

a.valueOf();
// 0
复制代码

咱们获得0了,这很合理,由于0就是赋给a.num的值。那咱们能够来作几个测试:

typeof a.valueOf();
// "number"

a.num == a.valueOf()
// true
复制代码

很好,但为何这个很重要呢?

这很重要,由于当你两种不一样类型的遇到相等操做符的时候,js会对其进行类型转化——它企图将操做数的类型转化为相似的。

在咱们的问题中:(a==1 && a==2 && a==3)JavaScript会企图将对象转化成数字的类型,进行比较。当要转化的是一个Object的时候,JavaScript会调用valueOf()方法。

自从咱们改变了valueOf()方法以后,咱们能不能作到如下几点呢:

a == 0

// true
复制代码

咱们作到了,异常轻松。

如今咱们须要作的的一点是:当咱们每次去调用a的值的时候,能改变它。

幸运的是,在JavaScript中有+=符号。

+=这个运算符能够轻松的去改变一个的值,咱们能够举个简单的例子:

let b = 1
console.log(b+=1); // 2
console.log(b+=1); // 3
console.log(b+=1); // 4
复制代码

正如你所见的,咱们每次使用加法赋值运算符,可让咱们的变量增长。

因此咱们能够将这个观念用到valueOf()中。

a.valueOf = function() {
  return this.num += 1;
}
复制代码

当咱们每次调用valueOf的时候,他会将变量增长1返回给咱们。

随着这个改变,咱们来运行下面的代码:

const equality = (a==1 && a==2 && a==3);
console.log(equality); // true
复制代码

这就是它的工做原理。

记住下面两点:

  • 使用相等操做符,js会作强制类型转化
  • 咱们的对象每次调用valueOf()它的值会增长1

因此比较的时候咱们每次都能获得true。

  • 补充第二点的运算过程
a                     == 1   -> 
a.valueOf()           == 1   -> 
a.num += 1            == 1   -> 
0     += 1            == 1   ->
1                     == 1   -> true
a                     == 2   -> 
a.valueOf()           == 2   -> 
a.num += 1            == 2   -> 
1     += 1            == 2   ->
2                     == 2   -> true
a                     == 3   -> 
a.valueOf()           == 3   -> 
a.num += 1            == 3   -> 
2     += 1            == 3   ->
3                     == 3   -> true
复制代码

总结

谢谢你观看这个小实验,但愿你能从中学到东西,有兴趣的朋友也能够去个人github点个star,你的支持是我持续输出的动力,谢谢!!!

相关文章
相关标签/搜索