偷偷运行的逻辑 - 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

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

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,948评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,371评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,490评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,521评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,627评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,842评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,997评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,741评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,203评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,534评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,673评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,339评论 4 330
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,955评论 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,770评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,000评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,394评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,562评论 2 349