JavaScript数据类型转换

在知乎上刷面试题看到有关JavaScript的数据类型的题目,对这个方面的知识再次回顾。写这篇博客源于一道十分简单的面试题:

1
2
3
4
5
6
7
8
9
function greet(person) {
if (person == { name: 'amy' }) {
return 'hey amy'
} else {
return 'hey arnold'
}
}

greet({ name: 'amy' })//'hey arnold'=>为什么没输出'hey amy'(你们应该知道原因的)

但还是插一句:原因是当两个操作数均为对象时,对象是引用类型,它们作为对象进行比较,仅当它们引用相同对象时返回true。

数据类型的定义

数据类型的分类:

基本数据类型: string,boolean,number,symbol(es6新增),undefined,null

内置函数(内置对象): String,Number,Boolean,Function,Symbol,Array,Date,RegExp…..

引用数据类型: Object

数据类型的转换:

隐式转换:

隐式转换在ECMAScript中有所规范:

​ 对象(包括数组) 会首先被转换为相应的基本类型值, 如果返回的是非数字的基本类型值, 则再遵循以上规则将其强制转换为数字。
为了将值转换为相应的基本类型值, 抽象操作 ToPrimitive 会首先(通过内部操作DefaultValue ) 检查该值是否有 valueOf() 方法。 如果有并且返回基本类型值, 就使用该值进行强制类型转换。 如果没有就使用 toString() 的返回值(如果存在) 来进行强制类型转换。

1
2
3
4
//输出?请解析原理
var a = [1, 2];
var b = [3, 4];
console.log(a + b); //"1,23,4"

原理:当a+b运算操作时,由于a和b是用“+”连接,导致a和b都要先进行隐式强制类型转换,再做“+”运算。但是由于a和b是数组类型,需要进行取原始值操作,解析器会先对数组先调用valueOf函数,如果有该方法并且返回值是原始类型的话就是这个返回值;否则继续调用toString()方法,如果返回的是原始值,则利用这个返回值进行“加”运算;否则会抛出异常。最后数组a和b最终调用toString()函数输出“1,2”和“3,4”,再通过“+”运算得到结果.

1
2
3
4
5
6
7
undefined == null;  // true   
1 == true; // true
2 == true; // false
NaN == NaN; // false NaN不等于任何值
6+'1'; //61
6-'3'; //3
[] == false; // true

1.undefined与null相等,但不恒等(===)
2.一个是number一个是string时,会尝试将string转换为number
3.隐式转换将boolean转换为number,0或1
4.对于0、空字符串的判断,建议使用 “===” 。
5.“==”会对不同类型值进行类型转换再判断,“===”则不会。它会先判断两边的值类型,类型不匹配时直接为false。

宽松相等和严格相等 :

宽松相等规范: 比较x==y时,且x和y都有值,会产生true和false的情况,以下比较的情况有

  1. 如果x和y的数据类型相同时,就相当于x===y
  2. 当x是null和y是undefined,返回true
  3. 如果x的数据类型是Number和y的数据类型是String,返回的比较是x==ToNumber(y)
  4. 如果x的数据类型是Boolean,那么的比较是ToNumber(x)==y
  5. 如果x的数据类型是String, Number, or Symbol 和y的数据类型是Object 那么返回的是 x == ToPrimitive(y).

严格相等规范: 比较x===y时,且x和y都有值,会产生true和false的情况,以下比较的情况有

  1. 如果x和y的类型不同,返回false
  2. 如果x的数据类型是Number:

​ 2.1 如果x是NaN,返回false

​ 2.2 如果y是NaN,返回false

​ 2.3 如果x是-0和y是+0,返回true

​ 2.4 如果x是+0和y是-0,返回true

​ 2.5 如果x和y都是Number且值相等,返回true

显式转换:

一般来说,显式转换是指Number,String,Boolean构造函数,手动将各种类型的值,转换成数字、字符串或者布尔值。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
Boolean( "0" ); // true
Boolean( [] ); // true
Boolean({}); // true
Boolean( ""); // false
Boolean( 0 ); // false
Boolean( null ); // false

Number('1234') // 1234
Number('1234abcd') // NaN
Number('') // 0
Number(true) // 1
Number(null) // 0
Number(undefined) // NaN

String(123)//"123"
String("abc") //"abc"
String(null)//"null"

对象通过toString或valueOf方法转换为原始值,JS语言核心的内置类首先尝试使用valueOf(),再尝试使用toString()。

对象类型的转换稍微复杂些,对象参与基本类型数据运算时,首先是要将对象转换为基本类型。转换方法如下:

  1. 调用toString()方法,如果返回基本类型的值,则用String()构造方法转换该值。
  2. 如果toString()方法返回的不是基本类型,则再调用valueOf()方法,如果返回基本类型的值,则用String()构造方法转换该值。
  3. 如果valueOf()方法返回的也不是基本类型,就抛出错误,如谷歌抛出:Uncaught TypeError: Cannot convert object to primitive value
String转换对象
  1. 先调用toString()方法去获得原始类型的值,返回的是原始类型的值,那么调用String()构造函数去返回值
  2. 如果toString()返回的是对象,那么就要继续调用valueOf()去获得原始类型的值,返回的是原始类型的值,那么调用String()构造函数去返回值
  3. 倘若valueOf()返回的也不是基本类型,那么抛出错误异常
1
2
3
4
5
6
7
8
9
10
11
12
var a = {
i :10,
toString:function(){
console.log('tostring')
return this.i;
},
valueOf:function(){
console.log('valueof')
return this.i;
}
}
var b = String(a)//先调用toString,再调用String()构造函数
Number转换对象
  1. 先调用valueOf()方法去获得原始类型的值,返回的是原始类型的值,那么调用Number()构造函数去返回值
  2. 如果valueOf()返回的是对象,那么就要继续调用toString()去获得原始类型的值,返回的是原始类型的值,那么调用Number()构造函数去返回值
  3. 倘若toString()返回的也不是基本类型,那么抛出错误异常
1
2
3
4
5
6
7
8
9
10
11
12
var a = {
i :10,
toString:function(){
console.log('tostring')
return this.i;
},
valueOf:function(){
console.log('valueof')
return this.i;
}
}
var b = Number(a)//先调用valueOf,再调用Number()构造函数
Boolean转换对象

Boolean对象有六个值转换十分特殊,其他的转换为true

1
2
3
4
5
6
7
8
9
undefined  null  false  0(包括+0和-0)  NaN  空字符串('')
Boolean(undefined) //false
Boolean(null) //false
Boolean(false) //false
Boolean(0) //false
Boolean(NaN) //false
Boolean('') //false

Boolean([]) //true

参考链接

  1. [温故js][https://segmentfault.com/a/1190000005863067#articleHeader9]
  2. [ECMAScript规范][https://tc39.github.io/ecma262/#sec-abstract-equality-comparison]
  3. [MDN比较操作符][https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Operators/Comparison_Operators]


本文由 Abert 创作,采用 知识共享署名 4.0 国际许可协议。

本站文章除注明转载/出处外,均为本站原创或翻译,转载请务必署名。