在 JavaScript 中,当我们进行比较操作或者加减乘除四则运算操作时,常常会触发 JavaScript 的隐式类型转换机制,下面将介绍javaScript的数据类型及执行运算时遵循的类型转换规则。
一、javaScript 数据类型:
(1)值类型(基本类型、原始值):Undefined(未定义)、Null(空)、Boolean(布尔)、Number(数字)、String(字符串)、Symbol(ES6 新增数据类型, 类似于字符串类型, 通常用来作为对象的属性名,表示独一无二的值);
(2)引用数据类型(对象值):Object(对象),包括Array(数组)、Function(函数)、Date(日期)等除了基本类型之外的所有其他类型的值。
原始类型(基本类型):按值访问,可以操作保存在变量中实际的值。原始类型汇总中null和undefined比较特殊。
引用类型:引用类型的值是保存在内存中的对象。
与其他语言不同的是,JavaScript不允许直接访问内存中的位置,也就是说不能直接操作对象的内存空间。在操作对象时,实际上是在操作对象的引用而不是实际的对象。所以引用类型的值是按引用访问的。
二、javaScript 数据类型转换
1. 一般的类型转换可参照下面的类型转换表(包括引用类型向原始类型转换的范例):
初始值 | 转化为数值类型 | 转化为字符串类型 | 转化为 Boolean 类型 |
---|---|---|---|
false | 0 | "false" | false |
true | 1 | "true" | true |
0 | 0 | "0" | false |
1 | 1 | "1" | true |
"0" | 0 | "0" | true |
"1" | 1 | "1" | true |
NaN | NaN | "NaN" | false |
Infinity | Infinity | "Infinity" | true |
-Infinity | -Infinity | "-Infinity" | true |
"" | 0 | "" | false |
"20" | 20 | "20" | true |
"twenty" | NaN | "twenty" | true |
[ ] | 0 | "" | true |
[20] | 20 | "20" | true |
[10,20] | NaN | "10,20" | true |
["twenty"] | NaN | "twenty" | true |
["ten","twenty"] | NaN | "ten,twenty" | true |
function(){} | NaN | "function(){}" | true |
{ } | NaN | "[object Object]" | true |
null | 0 | "null" | false |
undefined | NaN | "undefined" | false |
2. 在比较运算与加法运算中,都会涉及将运算符两侧的操作对象转换为原始对象的操作,此过程实际上由javaScript引擎内部的抽象操作 ToPrimitive(input [, PreferredType]) 函数执行,当某个对象出现在了需要原始类型才能进行操作的上下文时,JavaScript 会自动调用 ToPrimitive 函数将对象转化为原始类型。该抽象操作接受一个参数input和一个可选的参数PreferredType。该抽象操作的目的是把参数input转化为非对象数据类型,也就是原始数据类型。如果input可以同时转化为多个原始数据,那么会优先参考PreferredType的值。转换过程参照表:
参数input 的数据类型 | 结果 |
---|---|
Undefined | 返回input自身 |
Null | 返回input自身 |
Boolean | 返回input自身 |
Number | 返回input自身 |
String | 返回input自身 |
Symbol | 返回input自身 |
Object | 执行下面的步骤:
若 PreferredType是Number,则:
若 PreferredType是String,则与PreferredType是Number的情况步骤相反,先调用toString()方法 :
若PreferredType未设置,则将 PreferredType默认为 Number ,按照PreferredType是Number的规则进行处理(Date日期对象会默认为String,按照String处理)。 |
三、javaScript 常用运算符规则
注:若两个操作数不是均为数字,则只有 + 号 会优先考虑转换为字符串(但若其中一个操作数为数字,另一个操作数为原始类型,则会将原始类型转化为Number),剩下的操作均优先转换为Number再进行计算。
1. 加法(+)
对于加法运算而言,JavaScript 首先会将操作符两侧的对象转换为 Primitive 类型,即先调用ToPrimitive函数,在适当的隐式类型转换可得出有意义的值的前提下,JavaScript 会先进行隐式类型转换,再进行运算。一般遵循如下规则:
(1)若两个操作数均为数值,则遵循常规加法计算;
(2)否则遵循下列规则:
- 若其中一个操作数为 NaN,则结果为 NaN;
- 若为 Infinity + Infinity,则结果为 Infinity;
- 若为 -Infinity + (-Infinity),则结果为 -Infinity;
- 若为 -Infinity + Infinity,则结果为 NaN;
- 若为 +0 加 +0,则结果为 +0;
- 若为 -0 加 -0,则结果为 -0;
- 若为 +0 加 -0,则结果为 +0;
- 若两个操作数均为字符串,则结果为 两个字符串拼接的结果:'0' + '1' = '01'
- 若其中一个为字符串,则将另一个操作数转化为字符串,再返回 两个字符串拼接起来的结果;
- 若其中一个为非数值类型或非字符串类型,则遵循ToPrimitive函数执行结果,再遵循字符串相加规则计算最后结果;
2. 减法(-)
javaScript减法执行遵循下列规则:
- 如果两个操作数都是数值,则执行常规的算术减法操作并返回结果
- 如果一个操作数是NaN,则结果是NaN
- 如果是Infinity减Infinity,则结果是NaN
- 如果是-Infinity减-Infinity,则结果是NaN
- 如果是Infinity减-Infinity,则结果是Infinity
- 如果是-Infinity减Infinity,则结果是-Infinity
- 如果是+0减+0,则结果是+0
- 如果是-0减+0,则结果是-0
- 如果是-0减-0,则结果是+0
- 如果有一个操作数是字符串、布尔值、null或undefined,则先在后台调用Number()函数将其转换为数值,然后再根据前面的规则执行减法计算。如果转换的结果是NaN,则减法的结果就是NaN
- 如果有一个操作数是对象,则调用对象的valueOf()方法以取得表示该对象的数值。如果得到的值是NaN,则减法的结果就是NaN。如果对象没有valueOf()方法,则调用其toString()方法并将得到的字符串转换为数值
3. 关系操作符:小于(<)、大于(>)、小于等于(<=)、大于等于(>=)
(1)若对两个数值进行比较时,则按照正常比较大小的规则返回一个布尔值;
(2)若对非数值进行比较时,则遵循下列规则:
- 若两个操作数都是字符串,则比较两个字符串对应的字符编码值;
- 若一个操作数是数值,则将另一个操作数转换为一个数值,再执行数值的比较;
- 若一个操作数是对象,则调用这个对象的valueOf()方法,并用得到的结果(按照javaScript 数据类型转换规则获得)根据前面的规则执行比较;
- 若一个操作数是布尔值,则先将其转换为数值,再执行比较;
- 例子:
var result1 = "Brick" < "alphabet";//true //字母B的字符编码为66,二字母a的字符编码为97 var result2 = "23" < "3";//true //两个操作数都是字符串,而字符串比较的是字符编码("2"的字符编码是50,而"3"的字符编码是51) var result3 = "23" < 3;//false //在比较字符串和数值时,字符串都会被转换为数值,然后再以数值的形式与另一个数值进行比较 var result4 = "a" < 3;//false //由于字母a不能转换为合理的数值,因此被转换成了NaN var result5 = NaN < 3;//false var result6 = NaN >= 3;//false //按照常理,如果一个值不小于另一个值,则一定是大于或等于另一个值。在与NaN比较时,都返回了false
4. 相等操作符
4.1 相等(==)、不相等(!=)
(1)相等(==):若两个操作数相等,则返回true;
(2)不相等(!=):若两个操作数不相等,则返回true;
(3)==、!= 操作符均会将操作数先强制转换后再比较其相等性:
转换规则为:
- 若一个操作输是布尔值,则在比较前先将其转换为数值(false转换为0,true转换为1);
- 若一个操作数是字符串,另一个操作数为数值,则在比较前先将字符串转换为数值;
- 若一个操作数是对象,另一个操作数不是,则调用对象的valueOf()方法,用得到的基本类型值按照前面的规则进行比较;
比较规则为:
- null == undefined,在比较相等性之前,不能将null和undefined转换为其他任何值;
- 若一个操作数是NaN,则 == 操作符返回false,而 != 操作符返回 true;
- 若两个操作数都是NaN,按照 NaN不等于NaN的规则, == 操作符返回false;
- 若两个操作数都是对象,则比较它们是不是同一个对象,若均指向同一个对象,则 == 操作符返回true,否则返回false,!= 操作符规则相反;
例:
表达式 值 null == undefined true "NaN" == NaN false 5 == NaN false NaN == NaN false NaN != NaN true "5" == 5 true false == 0 true true == 1 true true == 2 false undefined == 0 false null == 0 false
4.2 全等(===)、全不等(!==)
全等(===)操作符表示不仅两个操作数的值相同,类型也相同,而全不等(!==)则表示操作数的值和类型都不相同,即:
- 当两个操作数不需要进行类型转换就可相等时 全等(===)操作符 返回true;
- 当两个操作数不需要进行类型转换就不相等时 全不等(!==)操作符 返回true;
例:
var result1 = ("55" == 55);//true,转换后相等
var result2 = ("55" === 55);//false,不转换,字符串不等于数值
var result3 = ("55" != 55);//false,转换后相等
var result4 = ("55" !== 55);//true,不转换,字符串不等于数值
var result5 = (null == undefined);//true,因为它们是类似的值
var result6 = (null === undefined);//false,因为它们是不同类型的值
参考链接: