关于javascript:关于JS类型隐式转换的完整总结

45次阅读

共计 3379 个字符,预计需要花费 9 分钟才能阅读完成。

不论是在技术聊天群还是论坛里,总能碰到 x + y 等于多少的问题,比方 [] + {} == ?,如果你不理解其中的原理,那么就插不上话,只能眼睁睁地等大佬解答了。

Type

说到底还是 JS 类型转换的问题,首先咱们先复习一下 JS 的 7 种内置类型:

  • Number
  • String
  • Boolean
  • Null
  • Undefined
  • Object
  • Symbol

是不是感觉还有 Function,毕竟能用 typeof 获取到?不,函数、数组都是 Object 的子类型。

类型分为 根本类型 复合类型 两种,除了对象,其它都是根本类型。

To Primitive

发音:[ˈprɪmətɪv]
在对象的隐式转换中,对象须要先转成根本类型,并依照如下程序执行。

  1. 对象会先调用valueOf()
  2. 如果没有 valueOf 这个办法或者 valueOf 返回的类型不是根本类型,那么对象会持续调用 toString() 办法。
  3. 如果没有 toString 这个办法或者 toString 返回的类型不是根本类型,那么间接抛出 TypeError 异样。
Uncaught TypeError: Cannot convert object to primitive value

接着,咱们看下各个对象的转换实现

对象 valueOf() toString()
Object 原值 字符串 => ‘[object Object]’
Function 原值 字符串 => ‘function xyz() {…}’
Array 原值 字符串 => ‘x,y,z’
Date 数字工夫戳 字符串 => “Sat May 22 2021…”

其中,数组的 toString()能够等效为 join(',')
其中,数组 toString()时,遇到 null, undefined 都被疏忽,遇到 symbol 间接报错,遇到没有 toString()的对象也报错。

[1, null, undefined, 2].toString() === '1,,,2';

// Uncaught TypeError: Cannot convert a Symbol value to a string
[1, Symbol('x')].toString()

// Uncaught TypeError: Cannot convert object to primitive value
[1, Object.create(null)].toString()

To Number

一些非凡值转为数字的例子,等下要用到

Number("0") === 0;
Number("") === 0;
Number(" ") === 0;
Number("\n") === 0;
Number("\t") === 0;
Number(null) === 0;
Number(false) === 0;

Number(true) === 1;

Number(undefined); // NaN
Number("x"); // NaN

加减法 +-

加减法运算中遵循了一些隐式转换规则:

遇到对象先执行 ToPrimitive 转换为根本类型,而后依照根本类型的规定解决

({}).toString() === "[object Object]"
1 + {} === "1[object Object]"

[2, 3].toString() === "2,3"
1 + [2, 3] === "12,3"
[1] + [2, 3] === "1,2,3"

function test() {}
test.toString() === "function test() {}"
10 + test === "10function test() {}"

加法过程中,遇到字符串,则会被解决为 字符串拼接

下面的对象最初也都转成了字符串,遵循本条规定。接着来几个纯字符串的例子

1 + "1" === "11"
1 + 1 === 2
"1" + 1 === "11"
"1" + "1" === "11"

减法操作时,一律须要把类型转换为 Number,进行数学运算

3 - 1 === 2
3 - '1' === 2
'3' - 1 === 2

// [].toString() => "" => Number(...) => 0
3 - [] === 3

// {}.toString() => "[object Object]" => Number(...) => NaN
3 - {} // NaN

加法操作时,遇到非字符串的根本类型,都会转 Number

1 + true === 2
1 + false === 1
1 + null === 1
1 + undefined // NaN

+ x 和 +x 是等效的(以及 - x),都会强制转换成 Number

+ 0 === 0
- 0 === -0
1 + + "1" === 2
1 + + + + ["1"] === 2
// 负负得正
1 + - + - [1] === 2
// 负负得正
1 - + - + 1 === 2
1 - + - + - 1 === 0

1 + + [""] === 1

// ["1", "2"].toString() => "1,2" => Number(...) => NaN
1 + + ["1", "2"] // NaN

// 吃根香蕉🍌
("ba" + + undefined + "a").toLowerCase() === "banana"

回到一开始抛出的问题[] + {},这样太简略了吧?

[].toString() === "";
{}.toString() === "[object Object]";

[] + {} === "[object Object]";

对象字面量 {} 在最后面则不代表对象

不是对象是什么?是你的八块腹肌?别急,看看经典的例子

{} + [] === 0;
{a: 2} + [] === 0;

这啥玩意?说好的 ”[object Object]” 呢?

好吧,这是 {} 其实代表的是 代码块,最初就变成了+ [],依据后面的准则,数组先被转换成字符串"",接着因为 + x 的运算,字符串被转成数字0

那 {a: 2} 总该是对象了吧?其实这时候 a 不是代表对象属性,而是被当成了标签(label),标签这货色 IE6 就曾经有了。所以如果咱们写成 {a: 2, b: 3} + [] 这样是会报错的,逗号要改成分号能力通过编译。

symbol 不能加减

如果在表达式中有 symbol 类型,那么就会间接报错。比方 1 + Symbol("x") 报错如下:

Uncaught TypeError: Cannot convert a Symbol value to a number

宽松相等 ==

相等于全等都须要对类型进行判断,当类型不统一时,宽松相等会触发隐式转换。上面介绍规定:

对象与对象类型统一,不做转换

{} != {}
[] != {}
[] != []

对象与根本类型,对象先执行 ToPrimitive 转换为根本类型

// 小心代码块
"[object Object]" == {}
[] == ""[1] =="1"[1,2] =="1,2"

数字与字符串类型比照时,字符串总是转换成数字

"2" == 2
[] == 0
[1] == 1
// [1,2].toString() => "1,2" => Number(...) => NaN
[1,2] != 1

布尔值先转换成数字,再按数字规定操作

// [] => "" => Number(...) => 0
// false => 0
[] == false

// [1] => "1" => 1
// true => 1
[1] == true

// [1,2] => "1,2" => NaN
// true => 1
[1,2] != true

"0" == false
"" == false

null、undefined、symbol

null、undefined 与任何非本身的值比照后果都是 false,然而null == undefined 是一个特例。

null == null
undefined == undefined
null == undefined

null != 0
null != false

undefined != 0
undefined != false

Symbol('x') != Symbol('x')

比照 < >

比照不像相等,能够严格相等(===)避免类型转换,比照肯定会存在隐式类型转换。

对象总是先执行 ToPrimitive 为根本类型

[] < [] // false
[] <= {} // true

{} < {} // false
{} <= {} // true

任何一边呈现非字符串的值,则一律转换成数字做比照

// ["06"] => "06" => 6
["06"] < 2   // false 

["06"] < "2" // true
["06"] > 2   // true

5 > null     // true
-1 < null    // true
0 <= null    // true

0 <= false   // true
0 < false    // false

// undefined => Number(...) => NaN
5 > undefined // false

欢送纠正错误,欢送学习交换珍藏。我是原罪,一个极客。

正文完
 0