一行能装逼的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. Mongoose全面理解

    一.创建schemas 创建schemas的方式: 1 var userSchema = new mongoose.Schema({ 2 name: String, 3 email: String, ...

  2. POJ 2992 求组合数的因子个数

    求C(n,k)的因子个数 C(n,k) = (n*(n-1)*...*(n-k+1))/(1*2*...*k) = p1^k1 * p2^k2 * ... * pt^kt 这里只要计算出分子中素数因子 ...

  3. POJ 2763

    题意:给一个数,边之间有权值,然后两种操作,第一种:求任意两点的权值和,第二,修改树上两点的权值. #pragma comment(linker, "/STACK:1024000000,10 ...

  4. <转>2015-7-14面试题

    由于一些原因,最近打算换一份工作,主要目标是大型的互联网公司.在经历了上周三天小公司试水后,昨天终于开始正式的面试之旅了(其实接到面试通知的就几家公司

  5. 使用Myeclipse创建自定义签名debug keystore

    1.在已经创建后的android项目上右击鼠标,如图所示 2.选择next下一步 3.选择create new keystore 注意  这里密码要输入android 4.点击next,录入基本信息 ...

  6. get( )与getline( )区别

    get与getline区别不是很大,但一个明显的区别是get遇到 '\n '字符后便返回,这是 '\n '还在缓冲区中,所以下次读出来的将是 '\n ',而getline遇到 '\n '也返回,但它会 ...

  7. Vi不显示insert

    edit file :/etc/vim/vimrc.tiny set compatible -> set nocompatible or install vim

  8. 这个setDefaultCloseOperation写不写的区别是什么?

      2009-03-23 13:40提问者采纳   设置用户在此窗体上发起 "close" 时默认执行的操作.必须指定以下选项之一: DO_NOTHING_ON_CLOSE(在 W ...

  9. linux学习笔记3:linux的网络配置,rpm包,shell以及samba服务器的使用和安装

    1.linux下的shell<linux命令.编辑器和shell编程> (1)shell种类有很多,常用的有三种,在linux可以通过ls -l /bin/*sh 来显示所有已安装的she ...

  10. Iterator之java.util.ConcurrentModificationException

    在运行以下代码时,会报java.util.ConcurrentModificationException异常, public class Demo { public static void main( ...