当前位置: 首页 > news >正文

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

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

前言

有人会说,这个问题好奇葩,放在别的语言里,这要是能输出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 = 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,你的支持是我持续输出的动力,谢谢!!!

相关文章:

  • 阿里云启动API创新大赛 资源编排技术为场景赛题
  • 阿里云MaxCompute,用计算力让数据发声
  • Linux - ubuntu 设置固定ip和设置dns
  • 8-Socket网络编程
  • Linux下的tar压缩解压缩命令详解
  • CSS3第三天
  • SAP之ABAP吐槽
  • centos6.8 安装Python2.7后, yum出现“No module named yum”错误
  • 业界丨李飞飞达沃斯论坛直击,与美国银行、埃森哲CTO圆桌聊AI应用
  • SQLServer 进程无法向表进行大容量复制(错误号: 22018 20253)
  • 读懂 Deployment YAML - 每天5分钟玩转 Docker 容器技术(125)
  • [20180129]bash显示path环境变量.txt
  • 使用zabbix 监控nginx cache的缓存命中率(openresty版)
  • 栈实现走出迷宫(C++)
  • Vue | 一个支持数据抓取的JSON树组件
  • “Material Design”设计规范在 ComponentOne For WinForm 的全新尝试!
  • ES6 ...操作符
  • EventListener原理
  • gulp 教程
  • HomeBrew常规使用教程
  • JSDuck 与 AngularJS 融合技巧
  • LeetCode算法系列_0891_子序列宽度之和
  • Markdown 语法简单说明
  • Next.js之基础概念(二)
  • ng6--错误信息小结(持续更新)
  • spring cloud gateway 源码解析(4)跨域问题处理
  • SpriteKit 技巧之添加背景图片
  • ucore操作系统实验笔记 - 重新理解中断
  • 番外篇1:在Windows环境下安装JDK
  • 翻译 | 老司机带你秒懂内存管理 - 第一部(共三部)
  • 极限编程 (Extreme Programming) - 发布计划 (Release Planning)
  • 使用Maven插件构建SpringBoot项目,生成Docker镜像push到DockerHub上
  • 一加3T解锁OEM、刷入TWRP、第三方ROM以及ROOT
  • 白色的风信子
  • hi-nginx-1.3.4编译安装
  • 阿里云服务器如何修改远程端口?
  • ​ 轻量应用服务器:亚马逊云科技打造全球领先的云计算解决方案
  • ​【原创】基于SSM的酒店预约管理系统(酒店管理系统毕业设计)
  • ###C语言程序设计-----C语言学习(3)#
  • #if 1...#endif
  • #NOIP 2014# day.1 生活大爆炸版 石头剪刀布
  • #QT(TCP网络编程-服务端)
  • $redis-setphp_redis Set命令,php操作Redis Set函数介绍
  • (02)Hive SQL编译成MapReduce任务的过程
  • (1/2) 为了理解 UWP 的启动流程,我从零开始创建了一个 UWP 程序
  • (八)c52学习之旅-中断实验
  • (万字长文)Spring的核心知识尽揽其中
  • (一)【Jmeter】JDK及Jmeter的安装部署及简单配置
  • ****** 二 ******、软设笔记【数据结构】-KMP算法、树、二叉树
  • ***测试-HTTP方法
  • .bat批处理出现中文乱码的情况
  • .chm格式文件如何阅读
  • .class文件转换.java_从一个class文件深入理解Java字节码结构
  • .h头文件 .lib动态链接库文件 .dll 动态链接库
  • .mat 文件的加载与创建 矩阵变图像? ∈ Matlab 使用笔记