关于javascript:有趣的JS隐式类型转换

8次阅读

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

乏味的 JS- 隐式类型转换

当两个不同数据类型的操作数在做运算,或者操作数与操作符不匹配的时候,js 引擎不会报错,会把操作数转成对应的数据类型继续执行上来,这个转换是主动实现的,常常被叫做隐式类型转换。其实大部分开发者都或多或少理解过这一点,比方咱们常常会写这样的表达式 !!param 来确保参数是个 Boolen 值,+param确保是个数字,param + ''把参数转为字符串,然而总会遇到一些更简单的表达式,例如:
{1} + 3
3 + [1, 2]
‘1’ + +’3′
false == ![]
等等一大堆,那只有把规定理分明了,这些问题就迎刃而解了。次要就是这几种状况(疏忽 BigInt 和 Symbol 这两种不罕用的类型):

1. + 符号运算

这个运算符比拟非凡,先把它给拎进去,因为它既能够示意字符串连贯符号用来拼接两个字符串,又能够作为算数运算符做加法运算。这取决于运算符两边的数据类型

  1. 只有有一个是字符串:把另外一个操作数的数据类型转成 String 依照字符串拼接
  2. 否则把两个操作数转成 Number 类型做加法运算

转换规则是重点,在介绍转换规则之前先说下 JS 的数据类型,数据类型分为简略数据类型和简单数据类型,Undefined、Null、String、Number、Boolen 这 5 个属于简略的简略数据类型,它们的换规定如下:

类型 转 Number 转 String
Undefined NaN “undefined”
Null 0 “null”
Boolean true => 1; false => 0 true => ‘true’; false => ‘false’
Number 原样输入 负数 => ‘ 负数 ’; 正数 => ‘ 正数 ’; NaN => ‘NaN’; +0,-0 => ‘0’; Infinity => ‘Infinity’; -Infinity => ‘-Infinity’; 迷信计数法示意 => 对应的字符串; 非十进制数示意 => 十进制示意的字符串
String 根本是跟 Number 转字符串相同的,然而 8 进制数字字符串会转成去掉结尾 0 后的 10 进制数,16 进制数字字符串 => 10 进制数字;其余不转为数字的会转为 NaN 原样输入

对象的转换就比较复杂了,不会进行间接转换而是通过一系列的办法。
转 Number:

  1. 先调用它的 valueOf 办法,如果是简略类型则执行运算,返回后果
  2. 否则调用它的 toString 办法,如果是简略类型则执行运算,返回后果
  3. 否则抛出谬误Uncaught TypeError: Cannot convert object to primitive value

转 String,如果对象是日期 Date 类型

  1. 先调用它的 toString 办法,如果返回是简略类型则执行运算,返回后果
  2. 否则调用它的 valueOf 办法,如果是根本类型则执行运算,返回后果
  3. 否则抛出谬误Uncaught TypeError: Cannot convert object to primitive value

如果不是日期类型:则 1,2 步骤调换,先调用 valueOf 再调用 toString 补充一点:如果是数组转成 String 会先调用 join 办法再调用 toString

let obj = {};
obj.valueOf = function() {return 3};
obj.toString = function() {return '1'};

+obj // 输入 3
'1' + obj // 输入 '13'

obj.valueOf = function() {return {}};
+obj // 输入 1

let date = new Date();
date.valueOf = function() {return 3};
date.toString = function() {return 1};

+date // 输入 3
'1' + date // 输入 '11'

date.toString = function() {return {}}; 
'1' + date // 输入 '13'

ES6 对象新加了 Symbol.toPrimitive 办法,如果对象存在这个办法则执行这个办法转换,没有的话执行下面的规定。toPrimitive办法只有一个参数,会依据传入的类型转成对应的后果,这里有一点须要 留神:当作为字符串拼接的时候传入的参数是 default,String(params)调用的时候参数才会传入 string。对于 Date 类型应该是外部公有逻辑,试了下重写不论用,能够看下这个:https://tc39.es/ecma262/#sec-…

let obj = {};
obj.valueOf = function() {return 3};
obj.toString = function() {return '1'};

obj[Symbol.toPrimitive] = function(preferType) {if (preferType == "number") {return 666;}
    if (preferType == "string") {return '3';}
    return null;
}

+obj // 输入 666
'1' + obj // 输入 '1null',preferType 是 default
String(obj) // 输入 '3'

2. 关系运算符:>、<、==、===、>=、<=,!=

2.1 相等运算符

对于 === 运算符除了比拟值以外还会进行类型的比拟,如果两边类型不一样必定是不相等了
对于 == 号运算符:

  1. 如果两边都是援用类型(Object),存储的是内存地址,是不相等的([] == [] // false, {} == {} // false)
  2. 如果其中一个是 null 另一个是 undefined 返回 true
  3. 如果其中一个是 null 或者 undefined 另一个不是 null 也不是 undefined,返回 false
  4. 如果其中一个是 NaN,返回 false
  5. Infinity 除了与 Infinity 和 +Infinity 相比是 true 外,其余都是 false
  6. -Infinity 除了与 -Infinity 相比是 true 外,其余都是 false
  7. 剩下的状况会把两边的操作数按下面提到的转 Number 的规定转成数字做比拟,但如果两边的操作数都是字符串则依照从左到右顺次依照它们的 ASCII 码值比拟。例如 ’ac’ < ‘ab’ 后果是 false,因为字母 c 的 ASCII 码值要大于字母 b 的 ASCII 码值
2.2 其余关系运算符

依照 2.1 中规定 7 解决

3. 逻辑运算符(三目运算符、||、&&、!)、if 和 while 条件表达式

转成 Boolean 值运算,除了这几个值 undefined、null、0,+0、-0、”、NaN 以外都是 true

4. 算数运算符(*、/、-、%、++、–)和位运算符(|、&、~)

依照下面提到的转 Number 的规定,转成数字运算

其余状况

除了后面几种次要的状况,就剩下一些特例了

  • alert,这个函数会把参数转为字符串
  • { 结尾的语句会被当做代码块,跟上前面的语句的时候相当于一目运算符,依照一目运算符的规定执行。例如:{} + 1 相当于 +1
  • null <= 0 是 true,null >= 0 也是 true。因为 null == 0 是 false,null > 0 也是 false,所以 nul <= 0,同理 null >= 0

举荐几个链接:
https://tc39.es/ecma262/#sec-toprimitive
https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Symbol/toPrimitive
https://interglacial.com/javascript_spec/a-11.html#a-11.6.1

正文完
 0