偷偷运行的逻辑 - JavaScript隐式类型转换

Posted yancy

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了偷偷运行的逻辑 - JavaScript隐式类型转换相关的知识,希望对你有一定的参考价值。

将写作当成兴趣,并一直进行下去。曾经这是个小小的奢望,现在已经在逐步的实现中。

长话短说,既然是技术文,就不发这么多感慨了,接下来,一起进入今天的正题吧。

今天给大家分享的是 javascript 中的隐式类型转换问题。相信很多的小伙伴都曾被它困扰过,不论是开发中还是面试过程中。期望今天的分享能给你带来不一样的理解。也能让你之后不再为此烦恼。

1. 基本数据类型

我们都知道,在 javascript 中一共有 7 中数据类型。分别是 Object, Null, Undefined, String, Number, Boolean, Symbol。这些东西我们在平时的开发过程中每天无时无刻不在接触,这里我们不多赘述。

2. 强制类型转换

平时的使用过程中,我们会遇到很多数据类型不一致的问题,同样,强制将不同的数据类型转换为相同的数据类型也是很正常的操作;接下来,我们看看都有什么样的强制转换方法:

2.1 字符串 -> 数字

1. parseInt
parseInt(\'123\') // 123
parseInt(\'123abc\') // 123
parseInt(\'12.3abc\') // 12
parseInt(\'abc123\') // NaN

解释:

此方法只转换 以数字开头的,直到不是数字,然后转换结束,如果字符串不是以数字开头,则转换为 NaN

2. parseFloat
parseFloat(\'123\') // 123
parseFloat(\'12.3abc\') // 12.3
parseFloat(\'1.2.3abc\') // 1.2
parseFloat(\'abc1.23\') // NaN

解释:

规则同 parseInt ,只是注意小数点的转换,只能转换一个小数点,如果是多个小数点,则只保留一个。

3. Number
Number(\'123\') // 123
Number(\'12.3abc\') // NaN
Number(\'1.2.3abc\') // NaN
Number(\'abc1.23\') // NaN

解释:

此方法只转换 全数字 的字符串,如果字符串不是全数字。如\'12.3abc\',\'1.2.3abc\',\'abc1.23\'………… 的情况,统一转换为 NaN

4. 位运算

位运算的使用在前端是特别少的,以至于很多前端人员不清楚具体使用。下面我们来看看,如何使用位运算将字符串转换为数字

主要有以下几种操作方式可做转换

  • ~
  • << 左移
  • >> 右移

对于位运算的实际运算方式我们暂不做描述,本次只看如何使用它们将字符串转为数字

~~\'123\'    // 123 (这里是两个 ~~ 波浪线)
\'123\' << 0 // 123
\'123\' >> 0 // 123

解释:

使用方法跟 Number 相同。都是只能转换全数字的字符串。不为全数字的字符串,~转换为 NaN ,另外两种转换为 0

2.2 数字 -> 字符串

1. 使用 + 运算符。
\'\' + 123 // \'123\'
2. 使用 toString 方法
let num = 123
num.toString() // ‘123’
3. 使用 String 方法
let num = 123
String(num) // \'123\'

2.3 转换为布尔值

1. !! 方法。(双重否定即为肯定。使用双重非可以得到原始值转换的布尔值)
let num = 123
!!num // true

let str = \'123\'
!!str // true
2. Boolean 方法
let num = 123
let str = \'123\'
Boolean(123) // true
Boolean(\'123\') // true

注意:

JavaScript 中为 false 的情况:

  • \'\',"" 空字符串
  • 0 数字 0
  • undefined
  • null
  • NaN
  • false

3. 隐式类型转换

3.1 可触发隐式类型转换的操作

  • 四则运算 +, -, *, /
  • 比较 > < >= <= ==

    • 注意: === 是不会触发隐式类型转换的。
  • 判断 if, while

3.2 toStringvalueOf 说明

此两种方法是将复杂数据类型转换为原始值输出。

1. 调用 valueOf 方法后
  • String, Number, Boolean 返回的分别是 字符串值,数字值,布尔值。
  • Object, Array, Function 返回的是自身
  • Date 返回的是从开始到现在的毫秒值
2. 调用 toString 方法后
  • String, Number, Boolean 返回的本别是字符串类型的值
  • Object 返回的是 [object Object]
  • Array 返回的是 空字符串。因为在 Array 中重写了这个方法
  • function 返回的是函数本身的字符串
  • Date 返回的是时间,并非毫秒数

注意:

在获取原始值(toPrimitive)时,会先调用 valueOf 方法,如果返回的不是原始值(也就是说返回的不是基本数据类型),则会继续调用 toString 方法。如果还不是原始值。则会报错。

3.3 具体实例解析

请在查看解析之前尝试解答下方问题

// 数组
[] == ![]   // 1
[] == []    // 2
[] == false // 3
[] == true  // 4
[1] == 1    // 5
[] == 0     // 6
[12] < [13] // 7

// 对象
{} == {}    // 8
{} == !{}   // 9
{} != {}    // 10

// 结合版
[] + {}     // 11
{} + []     // 12
{} + {}     // 13
[] + []     // 14
{} + 1      // 15
1 + {}      // 16

答案来咯,准备好了没

1. [] == ![] 执行步骤
// 将原题中的 ![] 转换为原始值 --> ![] 为false
[] == false
// 将 [] 转换为原始值 [].valueOf() 返回自身,继续调用 toString 返回 空字符串
\'\' == false
// 将空字符串转换为 布尔值,空字符串为false
false == false
// 得到结果为 [] == ![] --> true
2. [] == []
比较的是地址,两个数组的地址不相同。结果为false
3. [] == false

解答步骤同第一题[] == ![]

4. [] == true

解答步骤同第一题[] == ![]

5. [1] == 1
// 将 [1] 获取原始值, 调用 valueOf 返回自身,继续调用 toString 返回 \'1\'
1 == 1
// 得到结果 [1] == 1 --> true
6. [] == 0
// 将 [] 获取原始值, 调用 valueOf 返回自身,继续调用 toString 返回 ‘’
‘’ == 0
// 将空字符串转换为数字 \'\' --> 0
0 == 0
// 得到结果 [] == 0 --> true
7. [12] < [13]
// 将左右都转换为原始值
\'12\' < \'13\'
// 得到结果 true
8. {} == {}

[] == []

9. {} == !{}

[] == ![] 不同的是,这里的 {} 转化为字符串之后为[object Object] 。 所以结果与 [] == ![] 相反

10. {} !== {}

{} == {} 反结果

11. [] + {}
// 将左右同时获取原始值。
\'\' + \'[object Object]\' = \'[object Object]\'
12. {} + []

如果右边的值不值一个字典格式,则会将大括号当成一个空块儿处理。也就是说此时的表达式可以被转换成如下表达式+ [],然后将 [] 先转为空串,然后转换为数字,得到数字0

所以: {} + [] == 0

13. {} + {}

左右两边都做对象处理,获取原始值

\'[object Object]\' + \'[object Object]\' = \'[object Object][object Object]\'
14. [] + []

获取左右的原始值,都转换为了空字符串。然后做字符串拼接

\'\' + \'\' = \'\'
15. {} + 1

{} + [] ,可变形为 + 1

16. 1 + {}

将右方的 {} 获取原始值,得到 \'[object Object]\' ,原式可变形为

1 + \'[object Object]\' = \'1[object Object]\'

4. 补充点

  • NaN 与任何值都不相等,包括它本身(这得多很,自己跟自己都不相等)
  • undefined 参与的任意一个四则运算,结果都为 NaN
  • 布尔值 true 转数字时,转为 1false 转为数字时为 0
  • 字符串之间比较大小,实际比较的是字符编码。如:a > A = 97 > 65 = true

好了,今天的文章就分享到这儿咯,并没有写太多的概念,只是让大家来多看下实际运行的结果。一通则百通,知晓了实际运行的过程,再遇到相似的问题就游刃有余了。

以上是关于偷偷运行的逻辑 - JavaScript隐式类型转换的主要内容,如果未能解决你的问题,请参考以下文章

Flow学习笔记

JavaScript系列文章:自动类型转换

前端面试 JavaScript— 对象转原始类型是根据什么流程运行的?

js隐式转换

Scala - 隐式转换

JavaScript数据类型