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

一、JS运算符的优先级

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

优先级从高到低:

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

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

二、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的表格

规则如下:

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

规则如下:

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

三、步步执行

先看最简单的子表达式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”。

计算(!(~+[])+{})[--[~+""][+[]]*[~+[]] + ~~!+[]]+({}+[])[[~!+[]]*~+[]]的更多相关文章

  1. 前端极易被误导的css选择器权重计算及css内联样式的妙用技巧

    记得大学时候,专业课的网页设计书籍里面讲过css选择器权重的计算:id是100,class是10,html标签是5等等,然后全部加起来的和进行比较... 我只想说:真是误人子弟,害人不浅! 最近,在前 ...

  2. 分享一个SQLSERVER脚本(计算数据库中各个表的数据量和每行记录所占用空间)

    分享一个SQLSERVER脚本(计算数据库中各个表的数据量和每行记录所占用空间) 很多时候我们都需要计算数据库中各个表的数据量和每行记录所占用空间 这里共享一个脚本 CREATE TABLE #tab ...

  3. C语言 · 薪水计算

    问题描述 编写一个程序,计算员工的周薪.薪水的计算是以小时为单位,如果在一周的时间内,员工工作的时间不超过40 个小时,那么他/她的总收入等于工作时间乘以每小时的薪水.如果员工工作的时间在40 到50 ...

  4. C语言 · 阶乘计算 · 基础练习

    问题描述 输入一个正整数n,输出n!的值. 其中n!=1*2*3*-*n. 算法描述 n!可能很大,而计算机能表示的整数范围有限,需要使用高精度计算的方法.使用一个数组A来表示一个大整数a,A[0]表 ...

  5. C语言 · 最大值与最小值计算

    输入11个整数,计算它们的最大值和最小值. 样例输入 0 1 2 3 4 5 6 7 8 9 10 样例输出 10 0   #include<stdio.h> int main(){ ]; ...

  6. 无法向会话状态服务器发出会话状态请求。请确保 ASP.NET State Service (ASP.NET 状态服务)已启动,并且客户端端口与服务器端口相同。如果服务器位于远程计算机上,请检查。。。

    异常处理汇总-服 务 器 http://www.cnblogs.com/dunitian/p/4522983.html 无法向会话状态服务器发出会话状态请求.请确保 ASP.NET State Ser ...

  7. SQL Server-聚焦计算列或计算列持久化查询性能(二十二)

    前言 上一节我们详细讲解了计算列以及计算列持久化的问题,本节我们依然如前面讲解来看看二者查询性能问题,简短的内容,深入的理解,Always to review the basics. 持久化计算列比非 ...

  8. SQL Server-聚焦计算列持久化(二十一)

    前言 上一节我们结束了Hash Match Aggregate和Stream Aggregate的讲解,本系列我们来讲讲关于SQL Server中的计算列问题,简短的内容,深入的理解,Always t ...

  9. javascript:逆波兰式表示法计算表达式结果

    逆波兰式表示法,是由栈做基础的表达式,举个例子: 5 1 2 + 4 * + 3 -  等价于   5 + ((1 + 2) * 4) - 3 原理:依次将5 1 2 压入栈中, 这时遇到了运算符 + ...

  10. 微信小程序中利用时间选择器和js无计算实现定时器(将字符串或秒数转换成倒计时)

    转载注明出处 改成了一个单独的js文件,并修改代码增加了通用性,点击这里查看 今天写小程序,有一个需求就是用户选择时间,然后我这边就要开始倒计时. 因为小程序的限制,所以直接选用时间选择器作为选择定时 ...

随机推荐

  1. BZOJ1221 [HNOI2001] 软件开发 【费用流】

    题目 某软件公司正在规划一项n天的软件开发计划,根据开发计划第i天需要ni个软件开发人员,为了提高软件开发人员的效率,公司给软件人员提供了很多的服务,其中一项服务就是要为每个开发人员每天提供一块消毒毛 ...

  2. linux 查看自己所在的公网ip

    curl members.3322.org/dyndns/getip 其他的方法还有: curl icanhazip.com curl ifconfig.me curl curlmyip.com cu ...

  3. HDU5056 BoringCount--线性扫一遍

    11754936 2014-09-29 10:08:45 Accepted 5056 31MS 392K 1257 B G++ czy 好简单的思路,怎么就没想到呢..... Boring count ...

  4. 一起来学Spring Cloud | 第五章:熔断器 ( Hystrix)

    在微服务项目中,一个系统可以分割成很多个不同的服务模块,不同模块之间我们通常需要进行相互调用.springcloud中可以使用RestTemplate+Ribbon和Feign来调用(工作中基本都是使 ...

  5. hadoop 学习(二)

    我们很荣幸能够见证Hadoop十年从无到有,再到称王.感动于技术的日新月异时,希望通过这篇内容深入解读Hadoop的昨天.今天和明天,憧憬下一个十年. 本文分为技术篇.产业篇.应用篇.展望篇四部分 技 ...

  6. Chrome查看同步状态

    最近Hosts不太稳定,翻出去之后安装了一些插件,那么会面临一些问题,比如插件是否已经同步成功,其它PC能否获取等等. 下面是一些查询同步状态的入口: https://www.google.com/s ...

  7. Linux内核配置选项

    http://blog.csdn.net/wdsfup/article/details/52302142 http://www.manew.com/blog-166674-12962.html Gen ...

  8. IntelliJ IDEA 默认需要进行maven的设置

    IntelliJ IDEA 默认需要进行maven的设置 需要指定maven的地址,指定settings.xml的地址: 可以默认的在user/.m2/下面放一个settings.xml文件: 学习: ...

  9. centos 7 卸載 mysql

    跟網上文章,安裝了一個mysqlwget http://repo.mysql.com/mysql-community-release-el7-5.noarch.rpm 記下卸載過程: 首先执行查看命令 ...

  10. 前端编程提高之旅(十)----表单验证插件与cookie插件

        实际项目开发中与用户交互的常见手法就是採用表单的形式.取得用户注冊.登录等信息.而当用户注冊或登录后又须要记住用户的登录状态.这就涉及到经常使用的两个操作:表单验证与cookie增删查找.   ...