js的隐式数据类型转换规则(一)原理篇

隐式类型转换

隐式数据类型转换通常发生在比较大小,是否相等,加减乘除等运算、或当前运行环境的默认输出类型为固定值时。

例如:使用非严格相等操作符(==)判断两个值是否相等时,如果两个值的类型不同(typeof),会将两个值隐式的转化为相同的类型后再执行严格相等的比较。(其中一个或者两个值都发生类型转换)

1.原始类型之间的转换使用Number(),String(),Boolean()。

原始值 转化为数值类型 转化为字符串类型 转化为布尔类型
false 0 “false”
true 1 “true”
+0或-0 ‘’+0”或”-0” false
1 “1” true
NAN “NAN” false
infinity “infinity” true
-infinity “-infinity” true
undefined NAN “undefined” false
null 0 “null” false
“” 0 false
“10” 10 true
“abcd” NAN true

2.当引用类型转换为基本类型时则使用ToPrimitive函数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
ToPrimitive(input, PreferredType?)的简单实现,代码来源于:https://zhuanlan.zhihu.com/p/29064256 

var ToPrimitive = function(obj,preferredType){
var APIs = {
typeOf: function(obj){
return Object.prototype.toString.call(obj).slice(8,-1);
},
isPrimitive: function(obj){
var _this = this,
types = ['Null','Undefined','String','Boolean','Number'];
return types.indexOf(_this.typeOf(obj)) !== -1;
}
};
// 如果 obj 本身已经是原始对象,则直接返回
if(APIs.isPrimitive(obj)) {return obj;}

// 对于 Date 类型,会优先使用其 toString 方法;否则优先使用 valueOf 方法
preferredType = (preferredType === 'String' || APIs.typeOf(obj) === 'Date' ) ? 'String' : 'Number';
if(preferredType==='Number'){
if(APIs.isPrimitive(obj.valueOf())) { return obj.valueOf()};
if(APIs.isPrimitive(obj.toString())) { return obj.toString()};
}else{
if(APIs.isPrimitive(obj.toString())) { return obj.toString()};
if(APIs.isPrimitive(obj.valueOf())) { return obj.valueOf()};
}
throw new TypeError('TypeError');
}
原始值 转化为数值类型 转化为字符串类型 转化为布尔类型
[] 0 “” true
[10] 10 “10” true
[1,2] NaN “1,2” true
[“10”] 10 “10” true
[“abcd”] NaN “abcd” true
function(){} NaN “function(){}” true
{} NaN “[object Object]” true

以下几种类型在转化为布尔值时为false,其它的均为true

null,undefined,0,””,NaN(共五种)

注意:如果使用new操作符创建的对象隐式转换为boolean类型都是true,哪怕是new String(”);

运行环境和操作符对隐式类型转换的影响

数据到底是被转化为number还是string受到运行环境和操作符的影响。

运行环境的影响

​ 很多内置函数期望传入的参数的数据类型是固定的,如:alert(value)方法,它期望传入的value值是一个string类型,但是如果我们传入的是number类型或者object类型等非string类型的数据的时候,就会发生数据类型的隐式转换。这就是环境运行环境对数据类型转换的影响

操作符的影响

  • 当+号作为一元操作符操作单操作数的时候,他就会将这个数转换为Number类型

  • 当+号作为二元操作符时,如果两个操作数中存在一个String类型的话,那么另外一个操作数也会无条件地转换为字符串.

  • 在第1步转换后,如果有运算元出现原始数据类型是”字符串”类型值时,则另一运算元作强制转换为字符串,然后作字符串的连接运算(concatenation)。

  • 当+号作为二元操作符时,如果两个操作数一个都不是字符串的话,两个操作数会隐式转换成数字类型(如果无法成功转换成数字,则变成NaN,再往下操作),再进行加法算数操作.

  • 当算数运算的操作符是+号以外的其他操作数时,两个操作数都会转成数字类型进行数字运算。

== 与!=操作符的运算规则

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
x==y的判断

1.如果x与y的类型(typeof)相同,存在以下几个特殊情况需要注意

a.如果x与y均为undefined,或null,返回true

b.如果x与y均为number类型,且至少有一个值为NAN,返回false

c.+0==-0,返回true

d.undefined==null,返回true

e.x,y均为某个对象的实例,返回true

2.如果 x,y 类型不一致,且 x,y 为 String、Number、Boolean 中的某一类型,则将 x,y 使用 toNumber 函数转化为 Number 类型再进行比较。

3.如果 x,y 中有一个为 Object,则首先使用 ToPrimitive 函数将其转化为原始类型,再进行比较。

复杂对象转换原理

复杂对象是以什么标准来判断ToPrimitive(input,preferredType)操作传入的preferredType值到底是number还是string呢?(可以见上面代码部分,这里做个简单说明)

  1. 如果运行环境非常明确的需要将一个复杂对象转换为数字则传入number如 Number(value) 和 +value 则传入number

  2. 如果运行环境非常明确的需要将一个复杂对象转换为字符串则传入string如String(value) 和 alert(value) 则传入string

  3. 如果是用+号连接两个操作数,操作数在确定确定其中只要有一个为字符串的时候另外一个操作数会转为字符串,ToPrimitive()会传入string,但是如果两个操作数都不能确定是字符串的时候则默认传入number进行数据类型转换(Date对象是一个例外,它会默认传入string)。

ToPrimitive的转换示例

1
2
3
4
5
["12"]+1;  //‘121’

["12"].valueOf() // ["12"]

["12"].toString() //"12"

首先对于这个引用类型preferredType参数默认会是number,这个时候调用传入对象的valueOf()方法,如果他的返回值类型是一个基本类型,那么就返回这个值,如果不是,则调用toString()方法,返回这个基本类型的值。

Copyright © 2018 - 2019 诗之花绪 All Rights Reserved.

UV : | PV :