一行能装逼的JavaScript代码

2016-06-28 野狗

一行神奇的JS代码,当时我就震

惊了,这不就是传说中的ZB神奇么… … 哈哈。

写本篇文章的缘由是之前看到了一段js代码,如下:

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

然后让大家运行,出来的结果让人有点出乎意料,请看:  

太风骚了有木有!如果有人诋毁前端瞧不起JS的话,那就可以把这段代码发给他了~

不过话说回来了,这到底是什么原理呢?为什么一堆符号运算结果竟然能是两个字符,而且恰巧还是个sb!

其实靠的是js的类型转化的一些基本原理,本篇就来揭密”sb”是如何炼成的。相信你如果能把这个理清楚了,以后遇到类型转化之类的题目,就可以瞬间秒杀了。

1   JS运算符的优先级

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

优先级从高到低:

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

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

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

2   JS的类型转化

预处理结束,接下来需要运用的就是javascript的类型转化知识了。我们先说说什么情况下需要进行类型转化。当操作符两边的操作数类型不一致或者不是基本类型(也叫原始类型)时,需要进行类型转化。先按运算符来分一下类:

  • 减号-,乘号*,肯定是进行数学运算,所以操作数需转化为number类型。

  • 加号+,可能是字符串拼接,也可能是数学运算,所以可能会转化为number或string

  • 一元运算,如+[],只有一个操作数的,转化为number类型

  

下面来看一下转化规则。

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

ToPrimitive(input, PreferredType?)

可选参数PreferredType是Number或者是String。返回值为任何原始值。如果PreferredType是Number,执行顺序如下:

  1. 如果input为primitive,返回

  2. 否则,input为Object。调用 obj.valueOf()。如果结果是primitive,返回。

  3. 否则,调用obj.toString(). 如果结果是primitive,返回

  4. 否则,抛出TypeError

  5. 如果 PreferredType是String,步骤2跟3互换,如果PreferredType没有,Date实例被设置成String,其他都是Number

2. 通过ToNumber()把值转换成Number,直接看ECMA 9.3的表格http://es5.github.io/#x9.3

规则如下:

参数 结果
undefined NaN
null +0
boolean true被转换为1,false转换为+0
number 无需转换
string 由字符串解析为数字。例如,”324″被转换为324

3. 通过ToString()把值转化成字符串, 直接看ECMA 9.8的表格http://es5.github.io/#x9.8

规则如下:

参数 结果
undefined “undefined”
null “null”
boolean “true” 或者 “false”
number 数字作为字符串。比如,”1.765″
string 无需转换

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

3   步步执行

先看最简单的子表达式16:+[]

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

 

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

 

大功告成!子表达式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”。

4   最后

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

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

  

如果有人瞧不起JS,请把这段代码发给他,如果他想知道答案,请把本文发给他~

 

微信扫一扫
关注该公众号

一行能装逼的JavaScript代码的更多相关文章

  1. 一行能装逼的JavaScript代码的延伸

    前段就是坑,入坑水真深. 先看看一个黑科技, 纳尼,这是什么东西. (!(~+[])+{})[--[~+""][+[]]*[~+[]] + ~~!+[]]+({}+[])[[~!+ ...

  2. 这些JavaScript编程黑科技,装逼指南,高逼格代码,让你惊叹不已

    Javascript是一门很吊的语言,我可能学了假的JavaScript,哈哈,大家还有什么推荐的,补充送那啥邀请码. 本文秉承着:你看不懂是你SB,我写的代码就要牛逼. 1.单行写一个评级组件 &q ...

  3. 高级Javascript代码

    Javascript是一门很吊的语言,我可能学了假的JavaScript,哈哈,大家还有什么推荐的,补充送那啥邀请码. 本文秉承着:你看不懂是你SB,我写的代码就要牛逼. 1.单行写一个评级组件 &q ...

  4. 【Python成长之路】装逼的一行代码:快速共享文件【华为云分享】

    [写在前面] 有时候会与同事共享文件,正常人的操作是鼠标右键,点击共享.其实有个装逼的方法,用python的一行代码快速实现基于http服务的共享方式. [效果如下] [示例代码] 在cmd窗口进入想 ...

  5. 【Python成长之路】装逼的一行代码:快速共享文件

    [Python成长之路]装逼的一行代码:快速共享文件 2019-10-26 15:30:05 华为云 阅读数 335 文章标签: Python编程编程语言程序员Python开发 更多 分类专栏: 技术 ...

  6. JavaScript装逼指南

    如何写JavaScript才能逼格更高呢?怎样才能组织JavaScript才能让别人一眼看出你不简单呢?是否很期待别人在看完你的代码之后感叹一句“原来还可以这样写”呢?下面列出一些在JavaScrip ...

  7. JavaScript 装逼指南

    Summary 本文秉承着 你看不懂是你sb,我写的代码就要牛逼 的理念来介绍一些js的装逼技巧. 下面的技巧,后三个,请谨慎用于团队项目中(主要考虑到可读性的问题),不然,leader 干你没商量. ...

  8. 翻译 | 一行 JavaScript 代码的逆向工程

    原文地址:Reverse Engineering One Line of JavaScript 原文作者:Alex Kras 译者:李波 校对者:冬青.小萝卜 几个月前,我看到一个邮件问:有没有人可以 ...

  9. 最全面的Git 使用规范装逼指南[转载]

    <!DOCTYPE html> <script type="text/javascript"> window.logs = { pagetime: {} } ...

随机推荐

  1. DrawerLayout一个简单的实例(与ActionBar无关)

    官方的Demo里有DrawerLayout的例子,涉及到ActionBar,这里不用ActionBar,手痒,写个超级简单的小Demo,备着以后或许会用到. 详细的内容,可以访问:http://blo ...

  2. Program B 暴力求解

    Given a sequence of integers S = {S1,S2,...,Sn}, you should determine what is the value of the maxim ...

  3. C语言中的getchar和putchar详解

    首先给出<The_C_Programming_Language>这本书中的例子: #include <stdio.h> int main(){    int c;     c ...

  4. 记录一些容易忘记的属性 -- UIView

    一个视图原来添加在某个父视图上,然后再将它添加到另外的一个视图上,这个视图会从原来的某个父视图中移除,添加到新的视图上. 子视图对象指针存在父视图的subviews数组中,说明,一个视图可以有多个子视 ...

  5. SharePoint表单和工作流 - Nintex篇(一)

    博客地址 http://blog.csdn.net/foxdave 本篇开始我将带大家去认识一个第三方的表单工作流工具--Nintex. 本篇将对该工具做一些简单的介绍. Nintex公司成立于200 ...

  6. Setup Factory 打包.netframework 2.0

    在setup factory 的安装目录下的Dependencies中新建目录dotnet20/并放入dotnetfx2.0.exe: Dependencies目录中再加xml文件dotnet20.x ...

  7. c++中,bool与int 的区别

    菜鸟一枚,为了观察区别,特地运行了下面几个语句 /*阅读程序回答问题, 1.bool类型的false对应数值?true呢? 2.非0整数对应bool型的?0呢? */ #include<iost ...

  8. 机器翻译(noip2010)

    分析:该题是经典的队列题目,直接用队列实现就可以.如果数据范围大一些的话还可hash判重! 这可以说是一道送分的题目,但是还有粗心的学生会在这里失分,主要原因是数组的范围定义的不合适,因为空间足够用, ...

  9. hdu1005 矩阵

    //Accepted hdu1005 0MS 248K #include <cstdio> #include <cstring> #include <iostream&g ...

  10. JVM值内存垃圾回收监控之jstat

    如何判断JVM垃圾回收是否正常?一般的top指令基本上满足不了这样的需求,因为top主要监控的是总体的系统资源,很难定位到java应用程序. Jstat是JDK自带的一个轻量级小工具.全称“Java ...