前言

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

大家可以试着运行一下这串代码

在这里插入图片描述

是不是输出的"sb"让人眼前一惊

在这里插入图片描述

肯定都会去想这个变相的骂人是怎么实现的

原始式子拆分

解这种题目,当然要把他们先按运算符给拆分开来,一步一步分析了
在这里插入图片描述

首先可以将原始的式子分为

  • 式子1 (!(~+[])+{})[–[~+""][+[]]*[~+[]]+~~!+[]]
  • 式子2 ({}+[])[[~!+[]]*~+[]]

并且式子1和式子2通过 “+” 运算符连接

拆分式子1 (!(~+[])+{})[–[~+""][+[]]*[~+[]]+~~!+[]]

式子1又可以分为

  • 式子3: (!(~+[])+{})
  • 式子4: --[[~+""][+[]]]*[~+[]]+~~!+[]

并且式子3和式子4通过 “[]” 连接

式子3又可以分为

  • 式子5: (!(~+[]))
  • 式子6: {}

并且式子5和式子6用 “+” 运算符连接

式子5 (!(~+[])) 结果

先来看式子5 (!(~+[]))

优先级为先执行+,然后执行~

所以+[] 一元+,触发toNumber,而[]的toNumber为0

所以现在变成了!(~0),而~是一元位运算 触发toInt32 所以 ~0为 -1

所以现在式子5成为了!(-1), 此时-1执行toBoolean为true

所以式子5为false

式子3 (!(~+[])+{}) 结果

式子3是式子5和式子6通过+链接 所以就是 false + {}

这是二元+,所以会对左右两边的值进行hint为空的也就是number时的toPrimitive,先执行valueOf,false的valueOf为false,为基本类型值直接返回,而{}经过valueOf后返回{},不为基本类型值,所以继续执行toString,{}.toString为"[object Object]"

执行完toPrimitive后,判断两边值是否有string类型,而这里的"[object Object]"是string类型,所以执行拼接操作

所以式子3为 “false[object Object]”

拆分式子4 --[[~+""][+[]]]*[~+[]]+~~!+[]

式子4可以分为

  • 式子7 --[[~+""][+[]]]*[~+[]]
  • 式子8 ~~!+[]

并且式子7和式子8通过 “+” 运算符连接

拆分式子7 --[[~+""][+[]]]*[~+[]]

式子7又可分为

  • 式子9 --[[~+""][+[]]]
  • 式子10 [~+[]]

并且式子9和式子10通过 “*” 运算符连接

拆分式子9 --[[~+""][+[]]]

式子9又可分为操作符–与

  • 式子11 [~+""]
  • 式子12 +[]

并且式子11和式子12通过 “[]” 连接

式子11[~+""] 结果

接下来分析式子11 [~+""]

同样先执行+,一元+会触发toNumber,"".toNumber为0,

所以此时为0,前面也说了0为-1

因此式子11为[-1]

式子12 +[] 结果

式子12 +[]

触发toNumber [].toNumber为 0

因此式子12为0

式子9 --[[~+""][+[]]] 结果

而式子11和式子12通过[]连接,又有–操作符在前

所以式子9为–[-1][0],这里[-1][0]取得就是-1这个数了,数组的取值而已,没多大问题,然后执行–

此时式子9为 -2

式子10 [~+[]] 结果

然后分析式子10 [~+[]]

同理,先+[] ,触发toNumber,为0 ,

[~0]为[-1],

所以式子10为[-1]

式子7 --[[~+""][+[]]]*[~+[]] 结果

式子7是式子9和式子10通过*连接的

所以式子7为 -2 * [-1]

而二元*运算符,会将左右两边值都进行toNumber,-2的toNumber为-2,[-1]的toNumber,会触发toPrimitive

先执行valueOf,返回的数组本身,不是基本类型值,因此执行toString,所以为"-1",为"-1"继续执行toNumber,所以为-1,

因此式子7为-2 * -1,式子7为2

式子8 ~~!+[] 结果

此时分析式子8 ~~!+[]

先执行+ ,触发toNumber,为0。

然后执行!0,0执行toBoolean,0变成false,所以!false为true

然后执行~true。 true执行toInt32,为1,所以~1为-2 ,

然后执行~-2,为1

所以式子8为1

式子4 --[[~+""][+[]]]*[~+[]]+~~!+[] 结果

而式子4是式子7和式子8通过+连接的

所以式子4为 2 + 1,式子4为3

式子1 结果

式子1是式子3和式子4通过[]连接的

所以式子1 为 “false[object Object]”[3]

所以式子1为下标为3的元素,也就是"s"

在这里插入图片描述

拆分式子2 ({}+[])[[~!+[]]*~+[]]

现在分析式子2 ({}+[])[[~!+[]]*~+[]]

式子2可分为

  • 式子13 ({} + [])
  • 式子14 [~!+[]]*~+[]

并且式子13和式子14通过 “[]” 连接

拆分式子14 [~!+[]]*~+[]

式子14可分为

  • 式子15 [~!+[]]
  • 式子16 ~+[] ,

并且式子15和式子16通过 “*” 运算符连接

式子13 ({} + []) 结果

现在分析式子13 ({} + [])

这是很经典的,前面也分析过,双元+,会对左右两边的值进行toPrimitive

hint值为空,所以执行hint为Number的[[DefaultValue]],所以先执行valueOf,而{} 和[]的valueOf都是返回本身,也都不是基本类型值

因此会继续执行toString,而{} 的toString为"[object Object]",而[]的toString为"",因此再判断左右两边值是否有string类型,两边都是string类型,所以进行拼接操作

所以 “[object Object]” + “”

所以式子13为"[object Object]"

式子15 [~!+[]] 结果

现在分析式子15 [~!+[]]

同理,先执行+[],触发toNumber,[]的toNumber为0

执行!0,0先toBoolean为false,然后!false为true

然后~true,true先toInt32为1

然后~1为-2

所以式子15为[-2]

式子16 ~+[] 结果

现在分析式子16 ~+[]

同理 先执行+[],为0,

然后~0

所以式子16为-1

式子14 [~!+[]]*~+[] 结果

式子14是式子15和式子16通过*连接

所以式子14为 [-2] * -1 ,而双元* ,会对左右两边的进行toNumber

[-2]的toNumber首先会触发toPrimtive,首先valueOf返回[-2],不是基本类型值,继续执行toString,为"-2","-2"再执行toNumber,为-2

而-1的toNumber当然就是-1

所以式子14为-2 * -1,所以式子14为2

式子2 结果

式子2是式子13和式子14通过[]连接

因此式子4为"[object Object]"[2]

因此式子2也就是索引为2的元素:“b”

在这里插入图片描述

最初的式子的结果

最初的式子是式子1和式子2通过+连接的

所以最初的式子为 “s” + “b”,双元+运算符

对两边值进行toPrimitive,首先执行valueOf,返回本身,且为基本类型值,所以返回"s"与"b"

执行完toPrimitive后,判断左右两边值是否有string类型,两边都为string类型,所以执行拼接操作

所以"s" + “b”,最初的式子为"sb",也是挺有趣的一句话鸭

在这里插入图片描述

总结

这算是一道考验对类型转换规范的题目,而且考的比较详细了,如果能够正确分析出来,可以说是类型转换掌握的差不多了!

Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐