当前位置: 首页 > news >正文

一行神奇的javascript代码

一行神奇的JS代码,是在一个博客园里面看到的,当时我就震惊了,这不就是传说中的ZB神奇么… … 哈哈(果断转载过来)。
写本篇文章的缘由是之前群里@墨尘发了一段js代码,如下:
(!(~+[])+{})[--[~+""][+[]]*[~+[]] + ~~!+[]]+({}+[])[[~!+[]]*~+[]]
然后让大家运行,出来的结果让人有点出乎意料,请看:
   <img class="alignnone" src="https://images0.cnblogs.com/blog/520134/201502/082132272662027.png" alt="" />
ZB<img class="size-full wp-image-1004 aligncenter" src="http://www.aliyue.net/wp-content/uploads/2016/06/ZB.jpg" alt="ZB" width="358" height="271" srcset="http://www.aliyue.net/wp-content/uploads/2016/06/ZB.jpg 358w, http://www.aliyue.net/wp-content/uploads/2016/06/ZB-300x227.jpg 300w" sizes="(max-width: 358px) 100vw, 358px" />
 
  太风骚了有木有!如果有人诋毁前端瞧不起js的话,那就可以把这段代码发给他了~
  不过话说回来了,这到底是什么原理呢?为什么一堆符号运算结果竟然能是两个字符,而且恰巧还是个sb!
  其实靠的是js的类型转化的一些基本原理,本篇就来揭密”sb”是如何炼成的。相信你如果能把这个理清楚了,以后遇到类型转化之类的题目,就可以瞬间秒杀了。
 
  首先要运用到的第一个知识就是js运算符的优先级,因为这么长一段运算看的人眼花,我们必须得先根据优先级分成n小段,然后再各个击破。优先级的排列如下表:
  优先级从高到低:
运算符说明
.[ ] ( )字段访问、数组索引、函数调用和表达式分组
++ — – ~ ! delete new typeof void一元运算符、返回数据类型、对象创建、未定义的值
* / %相乘、相除、求余数
+ – +相加、相减、字符串串联
<< >> >>>移位
< <= > >= instanceof小于、小于或等于、大于、大于或等于、是否为特定类的实例
== != === !==相等、不相等、全等,不全等
&按位“与”
^按位“异或”
|按位“或”
&&逻辑“与”
||逻辑“或”
?:条件运算
OP=赋值、赋值运算(如 += 和 &=)
,多个计算

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

   &amp;lt;img class="aligncenter" src="https://images0.cnblogs.com/blog/520134/201502/082136322195194.png" alt="" /&amp;gt;
  运算符用红色标出,有一点可能大家会意识不到,其实中括号[]也是一个运算符,用来通过索引访问数组项,另外也可以访问字符串的子字符,有点类似charAt方法,如:’abcd'[1] // 返回’b’。而且中括号的优先级还是最高的哦。
 
  预处理结束,接下来需要运用的就是javascript的类型转化知识了。我们先说说什么情况下需要进行类型转化。当操作符两边的操作数类型不一致或者不是基本类型(也叫原始类型)时,需要进行类型转化。先按运算符来分一下类:
  • 减号-,乘号*,肯定是进行数学运算,所以操作数需转化为number类型。
  • 加号+,可能是字符串拼接,也可能是数学运算,所以可能会转化为number或string
  • 一元运算,如+[],只有一个操作数的,转化为number类型
  下面来看一下转化规则。

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

  ToPrimitive(input, PreferredType?)
  可选参数PreferredType是Number或者是String。返回值为任何原始值.如果PreferredType是Number,执行顺序如下:(参考: http://es5.github.io/#x9.1)
  如果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的表格http://es5.github.io/#x9.3

  规则如下:
参数结果
undefinedNaN
null+0
booleantrue被转换为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无需转换
  规则就这么多,接下来实践一下,根据我们上面划分出的子表达式,一步一步将这个神奇的代码给执行出来。开工~
  先看最简单的子表达式16:+[]
  只有一个操作数[],肯定是转化为number了,根据上面的规则2,[]是个数组,object类型,即对象。所以得先调用toPrimitive转化为原始类型,并且PreferredType为number,这个参数表示更“倾向于”转化的类型,这里肯定是number了。然后首先调用数组的valueOf方法,数组调用valueOf会返回自身,如下:
   &amp;lt;img src="https://images0.cnblogs.com/blog/520134/201502/082141145472548.png" alt="" /&amp;gt;
  这个时候,我们得到一个空串“”,还没有结束,看上面的规则2描述,继续调用toNumber,转化为number类型,如下:
   &amp;lt;img src="https://images0.cnblogs.com/blog/520134/201502/082142461578100.png" alt="" /&amp;gt;
  大功告成!子表达式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的求法类似,过程如下:
  ①调用toPrimitive,发现是object类型
  ②调用valueOf,返回自身[-1]
  ③因为不是原始类型,继续调用toString,返回”-1″
  ④”-1″是原始类型了,然后调用toNumber,返回-1
  ⑤与-2相乘,返回2
  子表达式10:~~!+[],不多说了,答案1. 就是从右往左依次一元计算。
  有了9和10,我们来到了子表达式4,此刻它已经长这样了:2+1, 好,我不多说了。
  继续看表达式7:!(~+[]),~+[]=-1,这个根据上面已经知道了,那!-1是什么呢?这里要说一下这个感叹号,它是逻辑取非的意思,会把表达式转化为布尔类型,转化规则和js的Truthy和Falsy原则是一样的,后面跟数字的,除0以外都为false,后面跟字符串的,除空串以外都为false。这里的!-1当然就是false了。
  接下来这个表达式3:false+{}有点关键。一个布尔加一个对象,那这个{}应该先转化为原始类型,流程如下:
  ①调用toPrimitive,发现是object类型
  ②调用valueOf,返回自身{},
  ③不是原始类型,调用toString,返回”[object Object]”
  ④false与”[object Object]”相加,false先转化为字符串”false”
  ⑤相加得结果”false[object Object]”
  知道了表达式3和4,我们就可以来看表达式1了,此时它是这样的:”false[object Object]”[3],因为这个[]可以取字符串的子字符,像charAt一样,所以得到了结果”s”
  经过上面艰难的流程,我们拿到了字符”s”,也就是那张图的左半边,剩下的那个”b”,相同的原理可以搞出来,我这里就不一一演示了,留给你练练吧~
  回顾一下这个过程其实也不复杂,只是有一些需要重复劳动的,只要你掌握了运算的优先级,能把大串分解成一个个小串,然后运用类型转化的知识挨个处理就搞定了。怎么样,看到这里你还觉得神奇吗?
  如果有人瞧不起js,请把这段代码发给他,如果他想知道答案,请把本文发给他~
 
本文转载自:http://www.cnblogs.com/lvdabao/p/4280518.html

转载于:https://www.cnblogs.com/liuyanxia/p/5798483.html

相关文章:

  • Mybatis初体验
  • JSP_内置对象_out
  • ubuntu desktop解决系统启动后网络没有主动连接
  • 第6集_奇点和安迪吃饭2 吃野生鲫鱼
  • 老男孩教育-linux面试题-基础题1
  • Redis常用命令入门2:散列类型
  • mysql通过配置文件进行优化
  • linux基础概念和个人笔记总结(6)
  • 终身受益的九段话
  • 前后端分离 的趋势
  • PHP isset()与empty()的使用区别详解
  • CentOS 7系统LAMP配置PHP-FPM的示例
  • 从控制台输入输出,来进行数据库的插入和查询操作的小程序
  • 同一台router上同时配置DM*** Hub端和Easy*** Server端
  • An incompatible version 1.1.14 of APR based Apache Tomcat Native library is installed, while Tomcat
  • 【跃迁之路】【641天】程序员高效学习方法论探索系列(实验阶段398-2018.11.14)...
  • Android 控件背景颜色处理
  • es6(二):字符串的扩展
  • Linux编程学习笔记 | Linux多线程学习[2] - 线程的同步
  • python 学习笔记 - Queue Pipes,进程间通讯
  • 大型网站性能监测、分析与优化常见问题QA
  • 前端学习笔记之观察者模式
  • 新手搭建网站的主要流程
  • 移动端唤起键盘时取消position:fixed定位
  • 由插件封装引出的一丢丢思考
  • d²y/dx²; 偏导数问题 请问f1 f2是什么意思
  • 回归生活:清理微信公众号
  • 浅谈sql中的in与not in,exists与not exists的区别
  • !$boo在php中什么意思,php前戏
  • # 透过事物看本质的能力怎么培养?
  • $.proxy和$.extend
  • $NOIp2018$劝退记
  • (2/2) 为了理解 UWP 的启动流程,我从零开始创建了一个 UWP 程序
  • (7)STL算法之交换赋值
  • (BFS)hdoj2377-Bus Pass
  • (ISPRS,2023)深度语义-视觉对齐用于zero-shot遥感图像场景分类
  • (附源码)springboot宠物医疗服务网站 毕业设计688413
  • (附源码)计算机毕业设计SSM智能化管理的仓库管理
  • (剑指Offer)面试题41:和为s的连续正数序列
  • (十一)图像的罗伯特梯度锐化
  • (心得)获取一个数二进制序列中所有的偶数位和奇数位, 分别输出二进制序列。
  • (一)UDP基本编程步骤
  • (一)硬件制作--从零开始自制linux掌上电脑(F1C200S) <嵌入式项目>
  • (转)真正的中国天气api接口xml,json(求加精) ...
  • .【机器学习】隐马尔可夫模型(Hidden Markov Model,HMM)
  • .NET Core MongoDB数据仓储和工作单元模式封装
  • .NET简谈设计模式之(单件模式)
  • @31省区市高考时间表来了,祝考试成功
  • @Tag和@Operation标签失效问题。SpringDoc 2.2.0(OpenApi 3)和Spring Boot 3.1.1集成
  • [2016.7.Test1] T1 三进制异或
  • [Angular 基础] - 数据绑定(databinding)
  • [AX]AX2012 R2 出差申请和支出报告
  • [bzoj1006]: [HNOI2008]神奇的国度(最大势算法)
  • [BZOJ4016][FJOI2014]最短路径树问题
  • [C#7] 1.Tuples(元组)