一行能装逼的JavaScript代码

        一行神奇的js代码,当时我就震惊了,这不就是传说中的ZB神奇么… … 哈哈。写本篇文章的缘由是之前看到了一段js代码,如下:

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

        然后让大家运行,出来的结果让人有点出乎意料,"sb"。太风骚了有木有!如果有人诋毁前端瞧不起js的话,那就可以把这段代码发给他了~不过话说回来了,这到底是什么原理呢?为什么一堆符号运算结果竟然能是两个字符,而且恰巧还是个sb!
        其实靠的是js的类型转化的一些基本原理,本篇就来揭密”sb”是如何炼成的。相信你如果能把这个理清楚了,以后遇到类型转化之类的题目,就可以瞬间秒杀了。

\color{rgb(26, 177, 204)}{ 一、js运算符的优先级}

        首先要运用到的第一个知识就是js运算符的优先级,因为这么长一段运算看的人眼花,我们必须得先根据优先级分成n小段,然后再各个击破。优先级的排列如下表,优先级从高到低:

运算符 说明
[]   () 字段访问、数组索引、函数调用和表达式分组
++   —   -   ~   !   delete new typeof void 一元运算符、返回数据类型、对象创建、未定义的值
*   /   % 相乘、相除、求余数
+   -   + 相加、相减、字符串串联
<<   >>   >>> 移位
<   <=   >   >=   instanceof 小于、小于或等于、大于、大于或等于、是否为特定类的实例
==   !=   ===   !== 相等、不相等、全等、不全等
& 按位“与”
^ 按位“异或”
l 按位“或”
&& 逻辑“与”
ll 逻辑“或”
?: 条件运算
=   OP= 赋值、赋值运算(如 += 和 &=)
多个计算

根据此规则,我们把这一串运算分为以下16个子表达式:

image.png

        运算符用红色标出,有一点可能大家会意识不到,其实中括号[]也是一个运算符,用来通过索引访问数组项,另外也可以访问字符串的子字符,有点类似charAt方法,如:’abcd'[1] // 返回’b’。而且中括号的优先级还是最高的哦。

\color{rgb(26, 177, 204)}{ 二、js的类型转化}

        预处理结束,接下来需要运用的就是JavaScript的类型转化知识了。我们先说说什么情况下需要进行类型转化。
        当操作符两边的操作数类型不一致或者不是基本类型(也叫原始类型)时,需要进行类型转化。先按运算符来分一下类:
        减号-,乘号*,肯定是进行数学运算,所以操作数需转化为number类型。
        加号+,可能是字符串拼接,也可能是数学运算,所以可能会转化为number或string。
        一元运算,如+[],只有一个操作数的,转化为number类型。

下面来看一下转化规则。

1、 对于非原始类型的,通过ToPrimitive() 将值转换成原始类型:

        ToPrimitive(input, PreferredType?)。
        可选参数PreferredType是Number或者是String。返回值为任何原始值。如果PreferredType是Number,执行顺序如下:
        如果input为primitive,返回。
        否则,input为Object。调用 obj.valueOf()。如果结果是primitive,返回。
        否则,调用obj.toString(). 如果结果是primitive,返回。
        否则,抛出TypeError。
        如果 PreferredType是String,步骤2跟3互换,如果PreferredType没有,Date实例被设置成String,其他都是Number。

2、 通过ToNumber()把值转换成Number,直接看ECMA 9.3的表格

规则如下:

参数 结果
Undefined NaN
Null +0
Boolean true被转换为1,false转换为+0
Number 无需转换
String 由字符串解析为数字

3. 通过ToString()把值转化成字符串, 直接看ECMA 9.8的表格

规则如下:

参数 结果
Undefined "undefined"
Null "null"
Boolean true或false
Number 数字转换为字符串
String 无需转换

        规则就这么多,接下来实践一下,根据我们上面划分出的子表达式,一步一步将这个神奇的代码给执行出来。

\color{rgb(26, 177, 204)}{ 三、步步执行}

        先看最简单的子表达式16:+[]
        只有一个操作数[],肯定是转化为number了,根据上面的规则2,[]是个数组,object类型,即对象。所以得先调用toPrimitive转化为原始类型,并且PreferredType为number,这个参数表示更“倾向于”转化的类型,这里肯定是number了。然后首先调用数组的valueOf方法,数组调用valueOf会返回自身,如下:

  [].valueOf()
  []

        这个时候,我们得到一个空串“”,还没有结束,看上面的规则2描述,继续调用toNumber,转化为number类型,如下:

  Number("")
  0

        大功告成!子表达式16转化完毕,+[],最终得到0。来看子表达式15:[~+””]

        空串””前面有两个一元操作符,但是操作数还是只有一个,所以,最终要转化为的类型是number。看规则2吧,空串调用toNumber得到0。

        接下来是 ~ ,这是个什么东东呢?它是位运算符,作用可以记为把数字取负然后减一,所以 ~0 就是 -1 。

        别忘了,这个子表达式外头还包着中括号,所以最终的值为[-1],即一个数组,里面只有一个元素-1。

        接下来看子表达式13就简单了,把15、16求出来的填进去,就变成了这样:–[-1][0],取数组的第0个元素,然后自减,结果为-2,是不so easy!
        继续往上走,子表达式14:[~+[]]

        其实把15、和16的原理用上就非常明显了,答案[-1]

        继续来求子表达式9,此刻它已变成:-2[-1],有稍许不一样,不过没关系,我们还是按照规则来,运算符是乘号,当然是做数学运算,那后面的[-1]就得转化为number,与16的求法类似,过程如下:
        1)、调用toPrimitive,发现是object类型
        2)、调用valueOf,返回自身[-1]
        3)、因为不是原始类型,继续调用toString,返回”-1″
        4)、”-1″是原始类型了,然后调用toNumber,返回-1
        5)、与-2相乘,返回2
        子表达式10:~~!+[],不多说了,答案1. 就是从右往左依次一元计算。
        有了9和10,我们来到了子表达式4,此刻它已经长这样了:2+1, 好,我不多说了。

        继续看表达式7:!(+[]),+[]=-1,这个根据上面已经知道了,那!-1是什么呢?这里要说一下这个感叹号,它是逻辑取非的意思,会把表达式转化为布尔类型,转化规则和js的Truthy和Falsy原则是一样的,后面跟数字的,除0以外都为false,后面跟字符串的,除空串以外都为false。

        这里的!-1当然就是false了。

接下来这个表达式3:false+{}有点关键。一个布尔加一个对象,那这个{}应该先转化为原始类型,流程如下:
        1)、调用toPrimitive,发现是object类型
        2)、调用valueOf,返回自身{},
        3)、不是原始类型,调用toString,返回”[object Object]”
        4)、false与”[object Object]”相加,false先转化为字符串”false”
        5)、相加得结果”false[object Object]”

        知道了表达式3和4,我们就可以来看表达式1了,此时它是这样的:”false[object Object]”[3],因为这个[]可以取字符串的子字符,像charAt一样,所以得到了结果”s”

\color{rgb(26, 177, 204)}{ 四、最后}

        经过上面艰难的流程,我们拿到了字符”s”,也就是那张图的左半边,剩下的那个”b”,相同的原理可以搞出来,我这里就不一一演示了,留给你练练吧。

        回顾一下这个过程其实也不复杂,只是有一些需要重复劳动的,只要你掌握了运算的优先级,能把大串分解成一个个小串,然后运用类型转化的知识挨个处理就搞定了。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,033评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,725评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,473评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,846评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,848评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,691评论 1 282
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,053评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,700评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,856评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,676评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,787评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,430评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,034评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,990评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,218评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,174评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,526评论 2 343

推荐阅读更多精彩内容