再说这行代码之前,咱们先来预习一下知识.

我们都知道计算机操作系统分为32位或者64位.那么这个32位或64位指的是什么意思呢?其实,要想解释它并不难,其实这就是计算机处理数据的机制,32位表示计算机的CPU(中央处理

器)一次性能够处理32位的数据,计算机数据都是按位来存储的,单位就是8位(bit)=1字节(b).然后依次向上推,1kb (千字节)= 1024b(字节),1mb(兆字节)=1024kb(千字节),1GB(千兆字节) =

1024mb(兆字节).

说了这么多,与今天讲的有什么关系吗?那当然是有关系啦.

我们先来看一串代码,如下图所示:

然后再在浏览器上运行查看效果,如下图所示:

是不是很神奇?就特么一行常用的符号就能够输出"sb"这两个字母,简直太牛叉了.接下来,我就来分析其中原理.

首先在分析之前,我们还需要知道一点知识,那就是既然计算机是按位处理数据的,那么浏览器处理js代码中的数据自然也不例外.所以js当中就有一个基本的概念,那就是位操作符.

什么是位操作符?简单点来说,就是在最基本的层次上,按内存中数值的位来操作数值.通过计算机的位操作原理,我们就能明白位操作符的含义.但是有一点需要区别,那就是位操作符不能

直接操作64位的数值,而是先将64位的数值转换成32位的数值来操作.

而转换的数值有且只有两个,那就是0和1.0表示的是正数,1表示的是负数.由0和1组成的一长串的如0000 0000 0000 0000 0000 0000 0000 0000 (4 X 8 = 32)的数字就是所谓的机器码.

机器码就是按照二进制格式来存储数据的.所谓二进制,也就是只有0和1两个数字来存储.

而前31位都表示的是整数,第32位则表示一个数值的符号.也就是+或-号,你可以把它理解成数学上的正负数的符号.

正数可以直接二进制存储,负数则需要二进制补码.也就是说咱们先取负数的绝对值,也就是将负数转换为正数来取二进制码,然后再取反,这里的取反意思就是因为二进制只有0和1两种

数字,所以不言而喻,取反就是0变成1,1变成0.

然后在加上一个1,当二进制最后一位是1时,加一就需要进位前面的一个0变成1,然后这个最后一位1就变成0.

我们通常都是十进制数,如10,那么如何转化为二进制数呢,通过除以2,然后取余数,最后把余数倒排.,要一直除到商等于0时才不用继续除下去,然后取它们的余数,颠倒顺序排列.

比如10/2 商5,余数是0,商5不等于0,继续除下去,得商2,取余数为1,商还不等于0,继续除下去,得商为1,余数是0,再除一次,得商0,余数为1,此时商也是0,也就不能再除,然后把得到的余数排

列就是0101,然后倒排就是1010,没有用到的位用0补上,或者不补,这里为了便于理解,我们不上前面的28个0 得0000 0000 0000 0000 0000 0000 0000 1010.所以得出10的二进制数就

是1010.那么-10的二进制数就应该是先将10的二进制数求出得1010,然后取反0变1,1变0,得0101.因为最后一位是1,按照上面的说法,然后加一个1,得0110.

说了这么多,与今天的代码有什么意义吗?那是当然.在了解了位操作符之后,我们还要了解一个知识,那就是js运算符的优先级,如下图:

首先需要耐心看完以上符号对应的含义,至少把上面那串代码用到的对应的符号的含义搞清楚.然后我们就可以根据运算符的优先级规则,把上面那一串代码给分解成多个子表达式.

重点解释一下~表示对先对数字求负,然后再减1.!返回一个布尔值.然后就是转换规则问题,对于一个非原始数据类型的,会先将其转换为原始数据类型,原始数据类型.实际上就是

ToPrimitive()这个方法来转换.它有两个参数,第一个参数表示数据类型,第二个参数是数值或者字符串.如果第一个参数是原始数据,那么就返回原始值,即本身值.否则就是返回object对

象.至于什么是原始数据类型,实际上就是基本数据类型(字符串,布尔值,数值...相信后面不用我多说了吧).而第二个参数可返回任何原始值,如果是对象也返回它本身.

所以,接下来,我们把以上的长串代码给拆分.

先来看最左边的(!(~+[])+{}),我们知道()表示一个函数的调用或者是一个表达式的分组,所以我再拆分得到(~+[]),好了先看[]这个符号,其实就是一个空数组,空数组会被转换为0,为什么呢?

首先它调用了对象底层valueOf()方法返回数组本身,实际上此时就得到的是一个空值,空值在遇到+这样的运算符的时候就会先调用Number()函数,当然实际上最底层还有一个

toNumber()函数转换成一个可转换的数值型数据,然后再通过Number()函数转换成数值0.随后就变成了~ + 0,然后就是先取负,变-0,再减1变成-1,然后就变成了!-1,就会返回一个false的

布尔值(可通过查看!逻辑非的转换返回相关知识得知这里为何会返回false).

接下来又是一个表达式(false + {}),这个比较关键,首先来看{}这是一个空对象,很明显就会调用ToPrimitive()这个方法,首先数据类型是对象,所以返回object,其次调用这个方法时,发现第

二个参数也还是对象,所以也就返回object,所以(false + {})也就成了false[object,object].

好接下来继续,由于第二个有点长,我们知道一对中括号包起来表示一个数组的下标.

那么[--[~+""][+[]]*[~+[]]+~~!+[]]这么一长串,我们就可以这样,先看[~ + ""],首先""空串其实跟null一样都被转换成了数值0,然后~+0则就是-1,--运算符就是先自减1再参与运算所以就是-1-1

变成了-2.

再看[+[]]实际上通过以上的规则不难得出就是[0]所以也就变成了[-2][0],这个表示啥意思,就是一个数组只有-2一个元素,而现在要取下标为0也就是第一个元素即-2,所以也就返回了-2,接

下来看[~+[]]不言而喻可以得出是[-1],[-2]*[-1]这很明显会当成-2*(-1)自然也就得出了2.

接下来看~~!+[]这里实际上都是从右往左计算的,因为运算符的优先级问题,通过上面的图可以看出,所以这里就是先转换!+[]返回true,然后再转换为1,然后~~1,根据~是先对数字求反再减

1的规律得到这里实际上就是1,然后这么一长串符号就变成了[2+1]即[3],然后就变成了

false[object object][3],通过这么艰难的分析就得出了s这个字母,然后再来看这部分({}+[])[[~!+[]]*~+[]],先运算表达式里面,很明显对象+一个对象会得出什么,自然是[object,object],这里的

+很明显被当成了拼接的作用,不要忘了它不只是做加法运算,还做拼接符号呢.

然后后面依次得出结论[-2 * -1]得出[2],然后就是[object,object][2],取出b,所以sb这两个字由此而来.

(!(~+[])+{})[--[~+""][+[]]*[~+[]] + ~~!+[]]+({}+[])[[~!+[]]*~+[]]一行js代码的原理分析的更多相关文章

  1. vue项目 一行js代码搞定点击图片放大缩小

    一行js代码搞定xue项目需要点击图片放大缩小,其实主要用的是用到了vue:class的动态切换,内容比较简单.一开始我把维护的需求想得太复杂了,和测试小姐姐聊了一下才反应过来. 两个月不到跟了四个项 ...

  2. 如何编写高质量的js代码--底层原理

    转自: 如何编写高质量的 JS 函数(1) -- 敲山震虎篇   本文首发于 vivo互联网技术 微信公众号 链接:https://mp.weixin.qq.com/s/7lCK9cHmunvYlbm ...

  3. js封装的三级联动菜单(使用时只需要一行js代码)

    前言 在实际的项目开发中,我们经常需要三级联动,比如省市区的选择,商品的三级分类的选择等等. 而网上却找不到一个代码完整.功能强大.使用简单的三级联动菜单,大都只是简单的讲了一下实现思路. 下面就给大 ...

  4. 一行js代码识别Selenium+Webdriver及其应对方案

    有不少朋友在开发爬虫的过程中喜欢使用Selenium + Chromedriver,以为这样就能做到不被网站的反爬虫机制发现. 先不说淘宝这种基于用户行为的反爬虫策略,仅仅是一个普通的小网站,使用一行 ...

  5. AngularJS:一行JS代码实现控件验证效果

    如上图所示,我们需要实现如下这些验证功能: 控件都是必输控件 都需要控制最大长度 第一次打开页面,控件不能显示为错误状态 输入内容再清空后,必输控件需要显示为错误状态 只有所有输入合法后,发布按钮才能 ...

  6. 一行JS代码,解决DedeCMS TAG标签错误输入符号问题

    在维护内容的时候, Tag标签输入经常要来回切换输入法,  只能通过','号分隔.  中文用户, 输入法出来的经常是全角的, 经常弄错, 增加了检查的工作量,  现在只要一句JS代码, 就自动替换所有 ...

  7. 一行js代码实现时间戳转时间格式

    javascript时间戳转换,支持自定义格式,可以显示年,月,周,日,时,分,秒多种形式的日期和时间. 推荐一个JavaScript常用函数库 jutils jutils - JavaScript常 ...

  8. 将一行很长的js代码格式化输出方便查看

    之前的一行js代码,有2万多字符,打开这个网址,粘贴到左边空白框,点下面格式化: 参考下面文章: 数千行的js代码变成了一行,如何复原,该换行的换行,该对齐的对齐_开发工具_小邯韩的博客-CSDN博客 ...

  9. 拼团商品列表页 分析 js代码行位置对执行的影响和window.onload的原理 setTimeout传参

    w TypeError : Cannot set property 'innerHTML' of nullTypeError : Cannot set property 'value' of null ...

随机推荐

  1. Regular Expression Syntax

    python的正则表达式 正则表达式的概念 正则表达式是对字符串操作的一种逻辑公式,就是用事先定义好的一些特定字符.及这些特定字符的组合,组成一个"规则字符串",这个"规 ...

  2. Android开发——打造简单的Viewpager指示器

    准备工作: 1.两张不同颜色的小圆点图片,可以去阿里巴巴矢量图网站搜索 我把我使用的图片贴出来 2.一个简单的Viewpager的实现 下面是简单的Viewpager实现步骤: 1.布局文件使用Vie ...

  3. [DeeplearningAI笔记]Batch NormalizationBN算法Batch归一化_02_3.4-3.7

    Batch Normalization Batch归一化 觉得有用的话,欢迎一起讨论相互学习~Follow Me 3.4正则化网络的激活函数 Batch归一化会使你的参数搜索问题变得很容易,使神经网络 ...

  4. linux shell 中的 2>&1 用法说明

    linux中有三种标准输入输出,分别是 STDIN,STDOUT,STDERR,对应的数字是 0,1,2. STDIN 是标准输入,默认从键盘读取信息: STDOUT 是标准输出,默认将输出结果输出至 ...

  5. 04_Python Data Structures

    Python数据结构 数据结构:数据个体的存储 和 数据个体与个体之间关系的存储. Python中有:1.序列 2.映射类型 3.无序集合 序列:成员有序排列.通过下标偏移量进行访问.元组.字符串.列 ...

  6. 01_Python入门

    Python介绍 python的创始人为吉多·范罗苏姆(Guido van Rossum).1989年的圣诞节期间,吉多·范罗苏姆(中文名字:龟叔)为了在阿姆斯特丹打发时间,决心开发一个新的脚本解释程 ...

  7. spring mvc 中自定义404页面在IE中无法显示favicon.ico问题的解决方法。

    此处用的是jsp,控制层用的是ModelAndView, 具体解决方法如下: @RequestMapping(value = "notfound", method = Reques ...

  8. Linux设置DNS地址及清理DNS缓存方法

    1.设置DNS地址 编辑vim /etc/resolv.conf 文件. 增加DNS地址:nameserver ip. 2.清理DNS缓存 清理dns缓存: 通过重启nscd服务来达到清理dns缓存的 ...

  9. 个人微信接入图灵机器人(python版)

    准备工作 itchat,requests 注册图灵账号,创建机器人,获取API-KEY 代码实现 import itchat from itchat.content import * import j ...

  10. yii2 模块的创建及使用

    yii2 模型创建可以通过gii工具创建,方便快速yii2 可以在项目的根目录创建一个modules文件夹存放各个模块,当然,每个模块里还可以再创建模块 一.直接在项目根目录创建一个模块 看截图--& ...