也只有JavaScript可以写出这么离谱的代码了吧
今天,有个朋友给我发了一串神秘的字符( (!(~+[]) + {})[--[~+''][+[]] * [~+[]] + ~~!+[]] + ({} + [])[[~!+[]] * ~+[]] ),还要我在控制台打印一下试试

好家伙,原来JavaScrip还能这样玩,那这到底是什么原理呢?
字符串解析
这段代码是一个典型的 JavaScript 混淆代码,通过一系列运算和隐式类型转换来生成字符串。首先我们先解析一下这段字符串,不难发现,这个字符串可以划分为两个部分:

第一部分
(!(
+[]) + {})[--[+''][+[]] * [~+[]] + ~~!+[]]
拆解步骤:
~+[]+[]将空数组转换为数字0,~0按位取反得到-1。

[~+''][+[]]~+''先将空字符串转为数字0,再取反得到-1,即[-1]。
[+[]]等价于[0],因此[-1][0]得到-1。

--[~+''][+[]]
即--[-1][0],递减后得到-2。

[~+[]]
和前面的一样,即[-1]。~~!+[]+[]为0,!0为true,~~true两次取反得到1。

--[~+''][+[]] * [~+[]] + ~~!+[]
计算:-2 * -1 + 1 = 3。

!(~+[])~+[]为-1,!(-1)为false。

!(~+[]) + {}false转为字符串"false",与空对象拼接得到"false[object Object]"。

"false[object Object]"[3]
索引3对应的字符是's'。

第二部分
({} + [])[[~!+[]] * ~+[]]
拆解步骤:
({} + [])
空对象转为字符串"[object Object]",与空数组相加仍为"[object Object]"。

~!+[]+[]为0,!0为true,~true按位取反得到-2。

[~!+[]]
即[-2]。[~!+[]] * ~+[][-2]转为数字-2,~+[]为-1,计算:-2 * -1 = 2。

"[object Object]"[2]
索引2对应的字符是'b'。
合并结果
将两部分结果拼接:'s' + 'b' = 'sb'。

核心技巧
- 隐式类型转换
- 数组/对象通过
+运算转为字符串。 !、~、+等运算符触发类型转换(如+[] → 0,[]+{} → "[object Object]",+{}+[] → "NaN")。
- 数组/对象通过

- 按位运算
~用于生成特定数值(如-1、-2)。 - 数组索引
通过计算得到字符串索引(如3、2),提取目标字符。
实现一个代码混淆函数
通过对前面那串神秘字符的分析,我们也知道了它的核心思路就是通过JavaScript的隐式类型转换规则对字符进行转换,那么我们是不是可以将我们的代码也都转换成这些字符,来达到一个代码混淆的效果呢?
1、数字转换
- 0:
+[]将空数组转换为数字0 - 1:
![]将空数组转为 false ,!![]再次取反得到 true ,+!![]+号让true隐式转换为1 - 其他数字 都可以通过1和0进行加减乘除或拼接来得到
{
0: "+[]",
1: "+!![]",
2: "!![]+!![]",
3: "!![]+!![]+!![]",
4: "(!![]+!![]) * (!![]+!![])",
5: "(!![]+!![]) * (!![]+!![]) + !![]",
6: "(!![]+!![]) * (!![]+!![]+!![])",
7: "(!![]+!![]) * (!![]+!![]+!![]) + !![]",
8: "(!![]+!![]) ** (!![]+!![]+!![])",
9: "(!![]+!![]+!![]) ** (!![]+!![])",
}
2、字母转换
- undefined
([][[]]+[]) 相当于 [][0]+'' ,可以得到字符串 undefined

- false
(![]+[]) 相当于 !true+'' ,可以得到字符串 false

- true
(!![]+[]) 相当于 !!true+'' ,可以得到字符串 true

- [object Object]
({} + []) ,空对象转为字符串 "[object Object]",与空数组相加仍为 "[object Object]"。
- NaN
(+{}+[]) ,{}会被隐式转为数字类型,对象无法被解析成有效数字,所以会返回 NaN

- constructor
通过前面转换的字符串,我们可以拼接成完整的 constructor 字符串。

我们可以通过构造器来获取到更多的字符,比如:

3、其他字符
通过前面的方法我们就可以将大部分的字母都获取到了,但是还有部分字母获取不到,那么剩下的字母就和其他字符一样都可以通过下面这个方式来获取:
比如字母 U:
ASCII 码 U → 八进制转十进制 85 → 转义为 \125,那么我们可以直接这样获得字母 U

所以我们只需要想办法得到函数构造器即可,还是要用到前面提到过的 constructor ,我们知道数组有很多内置的函数,比如 at:

那么 at 方法的构造器就是一个函数,我们直接通过 constructor 就可以获取到一个函数构造器


这里用到的字母都可以通过简单的转换得到,把字母通过前面的方法转换替换掉就可以了

好了,到这里你就实现了一个简单的 JSFuck 了~
体验地址


源码
组件源码已开源到gitee,有兴趣的也可以到这里看看:gitee.com/zheng_yongt…
- 🌟觉得有帮助的可以点个star~
- 🖊有什么问题或错误可以指出,欢迎pr~
- 📬有什么想要实现的组件或想法可以联系我~
公众号
关注公众号『 前端也能这么有趣 』,获取更多有趣内容。
发送 加群 还可以加入群聊,一起来学习(摸鱼)吧~
说在后面
🎉 这里是 JYeontu,现在是一名前端工程师,有空会刷刷算法题,平时喜欢打羽毛球 🏸 ,平时也喜欢写些东西,既为自己记录 📋,也希望可以对大家有那么一丢丢的帮助,写的不好望多多谅解 🙇,写错的地方望指出,定会认真改进 😊,偶尔也会在自己的公众号『
前端也能这么有趣』发一些比较有趣的文章,有兴趣的也可以关注下。在此谢谢大家的支持,我们下文再见 🙌。
来源:juejin.cn/post/7503846429082468389