博客
关于我
只用这 6 个字符,就可以写出任意 JavaScript 代码!
阅读量:451 次
发布时间:2019-03-06

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

你可能在网上见过有人用 几个不同的字符写的各种稀奇古怪的 JavaScript 代码,虽然看起来奇怪,但是能正常运行!比如这个:

(!(~+[])+{})[--[~+""][+[]]*[~+[]] + ~~!+[]]+({}+[])[[~!+[]]*~+[]]

你猜运行结果是什么?你可以自己去控制台试一下。

看起来很神奇,但这到底是怎么回事呢?

事实上,你几乎可以用下面这 6 个字符写出任意的 JavaScript 程序:

[]()!+

很多人都知道这个技巧,但是没有多少开发人员知道它到底是如何工作的。今天,我们就来看看它背后的执行原理。我们的目标是用这几个字符来写出字符串“self”。姑且用这个字符串向 Self 语言致敬,JavaScript 的灵感来源之一就是它。

基本原理

我们之所以能够抛开其他字符不用,要归功于 JavaScript 的类型系统和数据类型转换机制。

这 6 个字符是这样各显神通的:[]可以用来创建数组,!+可以在数组上执行一些操作,再用()给这些操作分组。

先看一个简单的数组:

[]

数组前加上!会把它转成布尔值。数组被认为是真值,因此取非之后变成了false

![] === false

除非转换为类似类型,否则无法将不同类型的值加在一起。JavaScript 在进行转换时遵循一个预定义的规则:

在表达式2 + true中,JavaScript 会将true转成数字,得到表达式2+1

在表达式2 + "2"中,JavaScript 会将数字转成字符串,得到2 + "2" === "22"

这些转换规则还不算糟糕,但是对于其他类型,好戏马上来了。

JavaScript 数组强制转换

数组相加会转换成字符串并连接起来。空数组转换为空字符串,因此将两个数组相加将得到空字符串。

[] + [] === "" + "" === ""

数组跟其他类型值相加时也一样:

![] + [] === "false" + "" === "false"

惊不惊喜?我们得到了目标字符串"self"所包含的几个字符!

如果我们能产生一些数字,就可以按正确的顺序提取所需的字符:

"false"[3] === "s"(![] + [])[3] === "s"

那么,如何生成数字呢?

生成数字

前面提到了,可以把数组转成布尔值。那如果用加号+把它转成数字会怎样?

+[] === ???

JavaScript 会尝试调用数组的valueOf方法,但是发现不存在这个方法,然后就转而调用toString() 方法了。因此上面的代码等效于:

+[] === +""

将字符串转换为数字将产生以下结果:

+"42" === 42+"esg" == NaN+"" === 0

空字符串是一个 false值,跟 null,undefined和数字零类似,因此将其中任何一个转换为数字都会变成零:

+null === 0+undefined === 0+false === 0+NaN === 0+"" === 0

因此,将数组转换为数字需要先将其转换为字符串,最后转成 0:

+[] === +"" === 0

第一个数字已经造出来了!我们还需要更多数字,继续:

!0 === !false!false === true!0 === true

0 取否就得到一个为真的布尔值。为真的布尔值转成数字,就是1

+true === 1

有了 1,自然就可以得到2,所谓道生一,一生二,二生三,三生万物……

用上面的转换大法,可以轻松得到我们想要的这些数字:

1 === +true == +(!0) ==== +(!(+[])) === +!+[]1 === +!+[]2 === +!+[] +!+[]3 === +!+[] +!+[] +!+[]4 === +!+[] +!+[] +!+[] +!+[]

临门一脚,大功告成

总结下这些规则:

  • 数组属于真值,取否就得到 false![] // false
  • 数组相加时会转换成字符: [] + [] // ""
  • 空数组转成数字得到 0,再去否得到 true,再转成数字得到1 +(!(+[])) === 1

根据这些规则,我们就能得到想要的字符串。看下面这个示意图就很清楚了:

![] + [] === "false"+!+[] === 1(![] + [])[3] + (![] + [])[4] + (![] + [])[2] + (![] + [])[0]^^^^^^^^^^      ^^^^^^^^^^      ^^^^^^^^^^      ^^^^^^^^^^        "false"         "false"         "false"         "false"       ^^^^^^^^^^^^^   ^^^^^^^^^^^^^   ^^^^^^^^^^^^^   ^^^^^^^^^^^^^          s               e               l               f

最终的表达式就是这样:

(![] + [])[+!+[]+!+[]+!+[]] + (![] + [])[+!+[]+!+[]+!+[]+!+[]] + (![] + [])[+!+[]+!+[]] +(![] + [])[+[]]

整理下空格和换行,就是一行代码:

(![]+[])[+!+[]+!+[]+!+[]]+(![]+[])[+!+[]+!+[]+!+[]+!+[]]+(![]+[])[+!+[]+!+[]]+(![]+[])[+[]]

现在你应该明白了那些神奇 JavaScript 代码的原理了吧?发挥你的想象,看还能写出其他什么来?比如,2020 年刚到,来个 “Happy New Year”?

Anyway,Happy New Year!

更多前端技术干货尽在微信公众号:1024译站

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

你可能感兴趣的文章
MySQL SQL 优化指南:主键、ORDER BY、GROUP BY 和 UPDATE 优化详解
查看>>
MYSQL sql语句针对数据记录时间范围查询的效率对比
查看>>
mysql sum 没返回,如果没有找到任何值,我如何在MySQL中获得SUM函数以返回'0'?
查看>>
mysql sysbench测试安装及命令
查看>>
mysql Timestamp时间隔了8小时
查看>>
Mysql tinyint(1)与tinyint(4)的区别
查看>>
MySQL Troubleshoting:Waiting on query cache mutex
查看>>
mysql union orderby 无效
查看>>
mysql v$session_Oracle 进程查看v$session
查看>>
mysql where中如何判断不为空
查看>>
MySQL Workbench 使用手册:从入门到精通
查看>>
MySQL Workbench 数据库建模详解:从设计到实践
查看>>
MySQL Workbench 数据建模全解析:从基础到实践
查看>>
mysql workbench6.3.5_MySQL Workbench
查看>>
MySQL Workbench安装教程以及菜单汉化
查看>>
MySQL Xtrabackup 安装、备份、恢复
查看>>
mysql [Err] 1436 - Thread stack overrun: 129464 bytes used of a 286720 byte stack, and 160000 bytes
查看>>
MySQL _ MySQL常用操作
查看>>
MySQL – 导出数据成csv
查看>>
MySQL —— 在CentOS9下安装MySQL
查看>>