只用这 6 个字符,就可以写出任意 JavaScript 代码!

你可能在网上见过有人用 几个不同的字符写的各种稀奇古怪的 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
复制代码

最终的表达式就是这样:

(![] + [])[+!+[]+!+[]+!+[]] +
(![] + [])[+!+[]+!+[]+!+[]+!+[]] +
(![] + [])[+!+[]+!+[]] +
(![] + [])[+[]]
复制代码

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

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

作者:KaysonLi
链接:https://juejin.im/post/5e030041e51d45581c1aa097
来源:掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

原文地址:https://www.cnblogs.com/guchengnan/p/12111584.html

时间: 2024-10-08 09:31:59

只用这 6 个字符,就可以写出任意 JavaScript 代码!的相关文章

用6个字符写出任意的Javascript代码

博客搬到了fresky.github.io - Dawei XU,请各位看官挪步.最新的一篇是:用6个字符写出任意的Javascript代码.

如何写出无法维护的代码

如何写出无法维护的代码 酷壳里有很多我觉得很不错的文章,但是访问量最大的却是那篇<6个变态的Hello World>,和它能在本站右边栏“全站热门”中出现的还有“如何加密源代码”,以及编程真难啊等这样的文章.可见本站的读者们的偏好,我也相信你们都是“身怀绝技”的程序员.所以,今天给大家推荐这篇文章,相信一定能触动大家的兴奋点. 这篇文章的原文在这里(http://mindprod.com/jgloss/unmain.html),我看完后我想说—— 什么叫“创造力”,创造力就是——就算是要干一件

怎样写出无法维护的代码

每次写代码的时候,我都尽量写出一个尽可能方便其他人看得懂的代码,没办法,很多时候维护也是我自己,活着小的看不懂,还是我自己出手.但今天我想反其道而行之,怎样才能写出一份无法维护的代码. 原文在这里,原文翻译了一点,再加上自己的理解. 这个无法维护的代码是什么? 如果你的代码根本是别人看不懂,那不好意思,如果是我,我会尽可能另外写一份,或者一边看代码,一边注释,还有重命名,总之最后还是让我改了一遍就完事了.如果仅仅是这样,我觉得,还不是无法维护吧.应该看起来还算正常,而且有详细的注释,让人充满希望

力荐!这些工具可以帮你写出干净的代码

作者|Adeel Imran译者|无明 想写出好代码,却不知道从哪里开始?想删除死代码?想在代码库中找出未被使用的变量?想在代码中找出有问题的模式? 你是多元化团队的负责人吗?你的团队中有新来的开发人员吗?你担心他们会写出不符合标准的代码吗?在代码评审时是否花了一整天的时间去检查代码标准,而不是实际的逻辑实现? 我一直在做这样的事情,经常忙得像热锅上的蚂蚁.但从现在开始,我们要保证永远不再担心这类问题.在阅读本文过程中,如果遇到困难,可以参考代码库(https://github.com/adee

写出优质Java代码的4个技巧(转)

http://geek.csdn.net/news/detail/238243 原文:4 More Techniques for Writing Better Java 作者:Justin Albano 翻译:Vincent 译者注:如果现在要求对你写的Java代码进行优化,那你会怎么做呢?作者在本文介绍了可以提高系统性能以及代码可读性的四种方法,如果你对此感兴趣,就让我们一起来看看吧.以下为译文. 我们平时的编程任务不外乎就是将相同的技术套件应用到不同的项目中去,对于大多数情况来说,这些技术都

写出优质Java代码的4个技巧

我们平时的编程任务不外乎就是将相同的技术套件应用到不同的项目中去,对于大多数情况来说,这些技术都是可以满足目标的.然而,有的项目可能需要用到一些特别的技术,因此工程师们得深入研究,去寻找那些最简单但最有效的方法.本文我们将介绍一些有助于解决常见问题的通用设计策略和目标实现技术,即: 只做有目的性的优化 常量尽量使用枚举 重新定义类里面的equals()方法 尽量多使用多态性 值得注意的是,本文中描述的技术并不是适用于所有情况.另外这些技术应该什么时候使用以及在什么地方使用,都是需要使用者经过深思

不要把时间浪费在写出完美的代码

一个系统可能会持续工作5年,10年,20年甚至更长的时间.但是具体到这个系统中的某一行代码,即使是关于设计的部分,这一行代码存在的时间却会很短:几个月或者几天,甚至是几分钟. 一些代码比其他代码更重要 通过研究代码是怎么随时间改变的,Michael Feathers定义了一条代码变动曲线.每个系统都有很多写完之后就不再改变的代码.与此同时,也存在少量这样的代码,这些代码是整个系统最重要也是最有用的代码,它们会随时间一次又一次地改变.重构,或者被删除,重新来过,如是反复几次. 随着你对一个系统越来

10个编程小技巧,教你写出高质量代码!

你会写代码吗你会写高质量代码吗你知道怎么写高质量代码吗不要一上来就开始写代码想清楚,再动手今天,分享10个写代码的小技巧教你写出高质量代码↓↓↓ 1.重构思维模式 不要一上来就开始写代码,要掌握尽量多的重构方法,重构思维方式,掌握重构并不一定是要对原来代码的重构,而是让自己在操作之前就想好该怎么去进行. 2.搞清需求再动手 看到需求之后,肯定多多少少会有一些问题,或是理解上的错误,或是功能实现上的问题,这时,必须要交流清楚,否则,后续将会有更多问题. 3.文档也要写 可能不少人觉得文档没人看,写

小白程序员怎么由量变到质变写出高质量代码

小白程序员怎么由量变到质变写出高质量代码?很多老程序员从事开发多年,有这样一种感觉,查看一些开源项目,如Spring.Apache Common等源码是一件赏心悦目的事情,究其原因,无外两点: 1.代码质量非常高; 2.命名特别规范: 要写高质量的代码,不是一件容易的事,需要长年累月的锻炼,是一个量变到质变的过程,但要写好命名,只需要有比较好的英语语法基础和一种自我意识即可轻松达到. 1.切忌使用没有任何意义的英语字母进行命名. 2.切忌使用拼音,甚至是拼音首字母组合. 3.要使用英文,而且要使