摘要:让我们快速的复习一下在中一共有两种类型的值原始值和对象值原始值有布尔值数字还有字符串其他的所有值都是对象类型的值包括数组和函数类型转化先按运算符来分一下类减号,乘号,肯定是进行数学运算,所以操作数需转化为类型。
前言
很多小伙伴们觉得javaScript很简单,下面的这行 javaScript代码可能会让你怀疑人生。
(!(~+[])+{})[--[~+""][+[]]*[~+[]] + ~~!+[]]+({}+[])[[~!+[]]*~+[]]
小伙伴们学会了,以后遇到一些讲不通道理,让你不开森的人就把这段代码发给他。
那么这段代码为什么会输出sb呢?
其实这段代码考的是js的类型转化的一些基本原理
首先要运用到的第一个知识就是js运算符的优先级,因为这么长一段运算看的人眼花,我们必须得先根据优先级分成n小段,然后再各个击破
1, js运算符的优先级优先级的排列如下表:
优先级从高到低:
根据此规则,我们把这一串运算分为以下16个子表达式:
运算符用红色标出,有一点可能大家会意识不到,其实中括号[]也是一个运算符,用来通过索引访问数组项,另外也可以访问字符串的子字符,有点类似charAt方法,如:"abcd"[1] // 返回"b"。而且中括号的优先级还是最高的哦。
接下来需要运用的就是javascript的类型转化知识了,我们先说说什么情况下需要进行类型转化。当操作符两边的操作数类型不一致或者不是基本类型(也叫原始类型)时,需要进行类型转化。
让我们快速的复习一下.在JavaScript中,一共有两种类型的值:原始值(primitives)和对象值(objects).
原始值有:undefined, null, 布尔值(booleans), 数字(numbers),还有字符串(strings).
其他的所有值都是对象类型的值,包括数组(arrays)和函数(functions).
2.类型转化 (1)先按运算符来分一下类:减号-,乘号*,肯定是进行数学运算,所以操作数需转化为number类型。
加号+,可能是字符串拼接,也可能是数学运算,所以可能会转化为number或string
一元运算,如+[],只有一个操作数的,转化为number类型
(2)下面来看一下转化规则。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
通过ToNumber()把值转换成Number,直接看ECMA 9.3的表格
参数 | 结果 |
---|---|
undefined | NaN |
null | +0 |
布尔值 | true被转换为1,false转换为+0 |
数字 | 无需转换 |
字符串 | 由字符串解析为数字.例如,"324"被转换为324 |
如果输入的值是一个对象,则会首先会调用ToPrimitive(obj, Number)将该对象转换为原始值,然后在调用ToNumber()将这个原始值转换为数字.
通过ToString()把值转化成字符串, 直接看ECMA 9.8的表格
参数 | 结果 |
---|---|
undefined | "undefined" |
null | "null" |
布尔值 | "true" 或者 "false" |
数字 | 数字作为字符串,比如. "1.765" |
字符串 | 无需转换 |
如果输入的值是一个对象,则会首先会调用ToPrimitive(obj, String)将该对象转换为原始值,然后再调用ToString()将这个原始值转换为字符串.
规则就这么多,接下来实践一下,根据我们上面划分出的子表达式,一步一步将这个神奇的代码给执行出来。开工~
先看最简单的子表达式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个元素,然后自减,结果为-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",相同的原理可以搞出来,我这里就不一一演示了,留给你练练吧~
回顾一下这个过程其实也不复杂,只是有一些需要重复劳动的,只要你掌握了运算的优先级,能把大串分解成一个个小串,然后运用类型转化的知识挨个处理就搞定了。怎么样,看到这里你还觉得神奇吗?
同样的,中文字符也是由这样组成的,跟英文同样的道理。
参考https://www.cnblogs.com/ziyun...
https://zhidao.baidu.com/ques...
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/98127.html
摘要:前端培训初级阶段语法变量值类型运算符语句前端培训初级阶段内置对象函数前端培训初级阶段类模块继承基础内容知识我们会用到。 前端最基础的就是 HTML+CSS+Javascript。掌握了这三门技术就算入门,但也仅仅是入门,现在前端开发的定义已经远远不止这些。前端小课堂(HTML/CSS/JS),本着提升技术水平,打牢基础知识的中心思想,我们开课啦(每周四)。 该文为前端培训-初级阶段(1...
摘要:来,今天我来教大家一个骚操作。我利用的就是数组的索引来排序的,大家都知道,索引就是从开始,然后依次递增的。技术总结这个就是巧用了数组的索引,默认就是一个从小到大的排序的特性。 showImg(https://segmentfault.com/img/bVbsi8K);如果你想要对数组排序,可能会去百度去搜,于是有很多人教你用冒泡,什么二分插入排序、堆排序,如果不太懂其中的代码意思,很难...
摘要:原文来源于我的前言身为一种弱类型的语言,不用像语言那样要定义等等数据类型,因为允许变量类型的隐式转换和允许强制类型转换。 原文来源于我的github 0.前言 js身为一种弱类型的语言,不用像c语言那样要定义int、float、double、string等等数据类型,因为允许变量类型的隐式转换和允许强制类型转换。我们在定义一个变量的时候,就一个var、let、const搞定,不用担心...
摘要:今天的骚操作,分享的是一个自动拷贝电脑盘内容的程序。当别人的盘插入到你的电脑上时,脚本会自动把盘所有的内容,全部拷贝到你的电脑上。骚源码程序主要是由三个函数组成,。每个操作都会记录到日志中,以便日后查看相应的拷贝信息。 showImg(https://segmentfault.com/img/remote/1460000016794520); 阅读文本大概需要 6 分钟。 Python...
阅读 2800·2021-10-08 10:12
阅读 3889·2021-09-22 15:45
阅读 2443·2019-08-30 15:52
阅读 2537·2019-08-29 18:44
阅读 2562·2019-08-29 12:37
阅读 1065·2019-08-26 13:36
阅读 2486·2019-08-26 13:34
阅读 1373·2019-08-26 12:20