博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
JavaScript:(a==1 && a==2 && a==3)能输出true么?
阅读量:6510 次
发布时间:2019-06-24

本文共 2474 字,大约阅读时间需要 8 分钟。

如果你能确切的答出可以,那恭喜你,你可以绕道了

前言

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

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

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

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的隐式转化,真的有很多文章,我推荐一下以下几篇博客,如果你想要了解,可以点进去:

valueOf

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

我们举个例子:

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

我们可以对上述对象使用valueOf方法,他会返回一个对象。

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 = 1console.log(b+=1); // 2console.log(b+=1); // 3console.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   -> truea                     == 2   -> a.valueOf()           == 2   -> a.num += 1            == 2   -> 1     += 1            == 2   ->2                     == 2   -> truea                     == 3   -> a.valueOf()           == 3   -> a.num += 1            == 3   -> 2     += 1            == 3   ->3                     == 3   -> true复制代码

总结

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

转载地址:http://cebfo.baihongyu.com/

你可能感兴趣的文章
仿网易邮箱5.0版UI
查看>>
winsow xp不能安装软件, 提示"中断" 是因为设置了 软件限制策略
查看>>
as3调用外部应用程序 as调用外部exe文件as3调用bat文件 未测试
查看>>
linux kernel编译配置相关
查看>>
jQuery清空标签内容--防止内存泄露
查看>>
关于 HandlerMethodArgumentResolver 类 以及 WebArgumentResolver 类 自定义解析参数
查看>>
30个php操作redis常用方法代码例子
查看>>
设计模式:对问题行之有效的解决方式。其实它是一种思想。
查看>>
java异常—检查异常(checked exception)和未检查异常(unchecked exception)
查看>>
CodeForces 614B Gena's Code
查看>>
起床继续编程
查看>>
Thrift版本管理
查看>>
数据库备份那点事儿
查看>>
P2264 情书
查看>>
在C#代码中应用Log4Net(三)Log4Net中配置文件的解释
查看>>
雷林鹏分享:PHP 5 echo 和 print 语句
查看>>
各主流浏览器的区别
查看>>
Zigbee
查看>>
Android中Activity和Fragment与Fragment和Fragment之前互相传值方法
查看>>
阿里云搭建hadoop集群服务器,内网、外网访问问题(详解。。。)
查看>>