作者简介:
李中凯老师,8年前端开发,前端负责人,擅长JavaScript/Vue。
公众号:1024译站
掘金文章专栏:https://juejin.im/user/57c7cb8a0a2b58006b1b8666/posts
主要分享:Vue.js, JavaScript,CSS


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

最终的表达式就是这样:

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

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

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

本文已经获得李中凯老师授权转发,其他人若有兴趣转载,请直接联系作者授权。

作者简介:
李中凯老师,8年前端开发,前端负责人,擅长JavaScript/Vue。
公众号:1024译站
掘金文章专栏:https://juejin.im/user/57c7cb8a0a2b58006b1b8666/posts
主要分享:Vue.js, JavaScript,CSS

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

  1. web前端 - 写出漂亮JavaScript代码的实用技巧

    1.按强类型风格写代码 js是弱类型的,但是写代码的时候不能太随意,写得太随意也体现了编码风格不好.下面分点说明: (1)定义变量的时候要指明类型,告诉JS解释器这个变量是什么数据类型的,而不要让解释 ...

  2. 6个帮助你写出漂亮JavaScript代码的实用技巧

    来源 | www.fly63.com 我觉得写好代码和作文章差不多,无外乎:工整.优雅.拒绝重复.惜字如金.对代码有感情,每一行都应该尽心尽力,并且还要有把所有代码扔垃圾篓之后再重写两遍的冲动,一旦有 ...

  3. 如何写出漂亮的代码:七个法则

    如何写出漂亮的代码:七个法则. 首先我想说明我本文阐述的是纯粹从美学的角度来写出代码,而非技术.逻辑等.以下为写出漂亮代码的七种方法: 1, 尽快结束 if语句 例如下面这个JavaScript语句, ...

  4. 怎样写出无法维护的代码

    每次写代码的时候,我都尽量写出一个尽可能方便其他人看得懂的代码,没办法,很多时候维护也是我自己,活着小的看不懂,还是我自己出手.但今天我想反其道而行之,怎样才能写出一份无法维护的代码. 原文在这里,原 ...

  5. 如何写出无法维护的代码

    本文来自:酷壳--CoolShell 地址:https://coolshell.cn/articles/4758.html 如何写出无法维护的代码 2011年06月03日  陈皓 评论 120 条评论 ...

  6. 写出结构优雅代码的4个技巧

    写出结构优雅代码就像成为武林高手一样,需要积累思考勤学苦练.冰冻三尺非一日之寒.成熟的业界套路肯定是没有的,因为代码也有思想流派.现在是百家齐放的时代.code review时,一个不留神就会吵起来. ...

  7. 如何写出健壮的代码?

    简介:关于代码的健壮性,其重要性不言而喻.那么如何才能写出健壮的代码?阿里文娱技术专家长统将从防御式编程.如何正确使用异常和 DRY 原则等三个方面,并结合代码实例,分享自己的看法心得,希望对同学们有 ...

  8. java 快速生成有残午餐_写出优质Java代码的4个技巧

    译者注:如果现在要求对你写的Java代码进行优化,那你会怎么做呢?作者在本文介绍了可以提高系统性能以及代码可读性的四种方法,如果你对此感兴趣,就让我们一起来看看吧.以下为译文. 本文我们将介绍一些有助 ...

  9. 想要写出好味道的代码,你需要养成这些好习惯!

    无论做什么行业,良好的习惯会让我们受益终生.它就如我们的指南针一样,指引着我们的行动,从而走向成功. 养成良好的习惯,会让我们的工作更加顺利,生活也会变的更加清晰. 当我们久而久之习惯了做这些事情的时 ...

最新文章

  1. 用python画梵高星空-python 梵高
  2. 程序员如何明智地提出好的问题
  3. boost::math::negative_binomial用法的测试程序
  4. 深入理解javascript原型和闭包(8)——简述【执行上下文】上
  5. python3.6是用来干嘛的_学 Python 都用来干嘛的?
  6. 邮箱伪造漏洞、钓鱼邮件漏洞(未添加SPF导致)
  7. Spring Security UserDetail
  8. Unity3D基础14:碰撞检测
  9. mysql 完整性的概念_MySQL中一些深入概念整理
  10. 【协同任务】基于matlab蚁群算法多组群UAV协同任务路径规划【含Matlab源码 1578期】
  11. 2000坐标系xy坐标几位_2000国家大地坐标系
  12. 药品质量管理软件市场现状及未来发展趋势
  13. mysql 三表联查_MySql的join(连接)查询 (三表 left join 写法)
  14. html画布创建黑白象棋棋盘,canvas应用——中国象棋棋盘
  15. EM算法在直线分类与灭点检测中的应用(关于一篇文章的读后感)
  16. 四种方法解决:Windows10下使用SVN文件夹不显示小绿勾
  17. Linux上安装oracle19c客户端,Oracle 19c的下载和安装部署(图形安装和静默安装)
  18. ubuntu 制作本地源 离线安装
  19. SimpleITK笔记本中ITK细分(Segmentation)介绍
  20. js实现点气球小游戏

热门文章

  1. Matting Loss 总结
  2. win7查看隐藏文件_在Mac上查看隐藏文件的四个方法
  3. Github注册详细教程(含失败原因分析)
  4. 单表代换密码加密解密
  5. KeyStore 简述
  6. 阿里云ecs云服务器安装wdcp控制面板教程(推荐CentOS6.5)
  7. uni-app项目本地打包可在同机安装的不同apk
  8. 修改csdn博客中的个人简介
  9. “得到听书”和“樊登阅读”的体验感受
  10. postman测试接口出现404