JS类型隐式转换的完整总结

更新日期: 2021-05-23阅读: 1.6k标签: 类型

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


Type

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

Number

String

Boolean

Null

Undefined

Object

Symbol

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

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


To Primitive

发音:[ˈprɪmətɪv]
结构:toPrimitive(input, preferedType = number)
在对象的隐式转换中,对象需要先转成基本类型,并按照如下顺序执行。

对象会先调用valueOf()。

如果没有valueOf这个方法或者valueOf返回的类型不是基本类型,那么对象会继续调用toString()方法。

如果没有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..."
Date的默认preferedType=string,即在加法运算中先执行toString()。在 - | * | / | +x | -x 等运算中,先执行valueOf()

数组的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
原文:https://segmentfault.com/a/1190000040048164
作者:原罪


链接: https://fly63.com/article/detial/10319

JS中Null与Undefined的区别

在JavaScript中存在这样两种原始类型:Null与Undefined。这两种类型常常会使JavaScript的开发人员产生疑惑,在什么时候是Null,什么时候又是Undefined?Undefined类型只有一个值,即undefined。当声明的变量还未被初始化时,变量的默认值为undefined。

Javascript的类型检测

主要介绍了JS中检测数据类型的几种方式,typeof运算符用于判断对象的类型,但是对于一些创建的对象,它们都会返回\'object\',有时我们需要判断该实例是否为某个对象的实例,那么这个时候需要用到instanceof运算符

js类型转换的各种玩法

对于object和number、string、boolean之间的转换关系,ToPrimitive是指转换为js内部的原始值,如果是非原始值则转为原始值,调用valueOf()和toString()来实现。

JavaScript类型:关于类型,有哪些你不知道的细节?

Undefined类型表示未定义,它的类型只有一个值为undefined。undefined和null有一定的表意差别。非整数的Number类型无法使用 == 或 === 来比较,因为 JS 是弱类型语言,所以类型转换发生非常频繁

为你的 JavaScript 项目添加智能提示和类型检查

近在做项目代码重构,其中有一个要求是为代码添加智能提示和类型检查。智能提示,英文为 IntelliSense,能为开发者提供代码智能补全、悬浮提示、跳转定义等功能,帮助其正确并且快速完成编码。

js的类型

基本类型:按值访问,可以操作保存在变量中实际的值;引用类型数据存在堆内存,而引用存在栈区,也就是说引用类型同时保存在栈区和堆区,关于==的执行机制,ECMASript有规范,因为==前后的值交换顺序,返回的值也是一样的,所以在此对规范做出如下总结

再也不用担心 JavaScript 的数据类型转换了

JavaScript 是一种弱类型或者说动态类型语言。所以你不用提前声明变量的类型,在程序运行时,类型会被自动确定,你也可以使用同一个变量保存不同类型的数据。

JavaScript基础之值传递和引用传递

js的值传递和引用(地址)传递:js的5种基本数据类型 number,string,null,undefined,boolean 在赋值传递时是值传递,js的引用数据类型(object,array,function)进行引用传递,其实底层都是对象。

JS中的布尔 数字 字符串

JS中所有的值都可以转换成布尔类型 使用Boolean()或者 !!(两个感叹号),JS中所有的值都可以转换成数字类型,使用Number()或+。数字类型转换场景目的只有一个,用于计算,将后台传递的数据,从字符串转换为数字并参与计算

if条件中,js的强制类型转换

众所周知,JS在很多情况下会进行强制类型转换,其中,最常见两种是:1.使用非严格相等进行比较,对==左边的值进行类型转换2.在if判断时,括号内的值进行类型转换,转化为布尔值

点击更多...

内容以共享、参考、研究为目的,不存在任何商业目的。其版权属原作者所有,如有侵权或违规,请与小编联系!情况属实本人将予以删除!