Undefined类型的值转换为NaN
Null类型的值转换为0
Boolean类型的值,true转换为1,false转换为0
String类型的值转换如同使用Number()函数进行转换,如果包含非数字值则转换为NaN,空字符串为0
Symbol类型的值不能转换为数字,会报错
对象(包含数组)会首先被转换为相应的基本类型值,如果返回的是非数字的基本类型值,则再遵循以上规则将其强制转换为数字。
为了将值转换为相应的基本类型值,抽象操作ToPrimitive会首先(通过内部操作DefaultValue)J检查该值是否有valueOf()方法。如果有并且返回基本类型值,就使用该值进行强制类型转换。如果没有就使用toString()的返回值(如果存在)来进行强制类型转换。
如果valueOf()和toString()均布返回基本类型值,会产生TypeError错误。
通过函数parseInt(t),可以解析一个字符串,并返回一个整数,语法为parseInt(tsring,radix)
string:被解析的字符串
radix:表示要解析的数字的基数,默认是十进制,如果radix<2或者>36,则返回NaN
以下这些是假值:
假值的布尔强制类型转换结果都为false,从逻辑上说,假值列表以外的都应该是真值。
|| 和 && 首先会对第一个操作数执行条件判断,如果其不是布尔值就先强制转换为布尔类型,然后再执行条件判断。
|| 和 &&返回它们其中一个操作数的值,而非条件判断的结果
‘==’:不全相等,只比较数据,不比较类型,如果两边的类型不一致,则会进行强制类型转换后再进行比较
‘====’:全等,既要比较数据,也比较数据类型,如果两边的类型不一致时,不会做强制类型转换,直接返回false
(1)==主要存在:强制转换成number,null==undefined
" " == 0 //true
"0" == 0 //true
" " != '0' //true
123 == '123' //true
null == undefined //true
(2)Object.is():一般情况下和三等好的判断相同,它处理了一些特殊的情况,比如-0和+0不再相等,两个NaN是相等的
主要的区别就是 +0 != -0 而 NaN==NaN
在JavaScript中,基本类型是没有属性和方法的,但是为了便于操作基本类型的值,在调用基本类型的属性和方法时JavaScript会在后台隐式地将基本类型的值转换为对象,例如:
const a = 'abc';
a.length; //3
a.toUpperCase(); //ABC
在访问‘abc’.length时,JavaScript将‘abc’在后台转换成String('abc'),然后再访问其length属性。
JavaScript也可以使用Object函数显式地将基本类型转换为包装类型:
let a = 'abc'
Object(a) //String{'abc'}
也可以使用valueOf方法将包装类型倒转成基本类型:
let a = 'abc'
let b = Object(a)
let c = b.valueOf() //abc
看看如下代码会打印出什么:
let a = new Boolean(false);
if(!a){
console.log('Oops');
}
答案是什么都不会打印出来,因为虽然包裹的基本类型是false,但是false被包裹成包装类型后就成了对象,所以其非值为false,所以循环体中的内容不会运行。
首先看ToPrimitive方法,这是JavaScript中每个值隐含的自带的方法,用来将值(无论是基本类型值还是对象)转换为基本类型值。如果值为基本类型,则直接方法会值本身;如果值为对象,看起来就如下所示:
ToPrimitive(obj,type)
type的值为number或者string
(1)当type为number时规则如下:
(2)当type为string时规则如下:
可以看出两者的主要区别在于调用toString和valueOf的先后顺序。默认情况下:
总结上面的规则,对于Date以外的对象,转换为基本类型的大概规则可以概括为一个函数:
let objToNumber = value => Number(valueOf().toString())
objToNumber([]) === 0
objToNumber({}) === NaN
而JavaScript中的隐式类型转换主要发生在+、-、*、/以及==、>、<这些运算符之间。而这些运算符只能操作基本类型值,所以在进行这些运算前的第一步就是将两边的值用ToPrimitive转换成基本类型,再进行操作。
一下是基本类型的值在不同操作符的情况下隐式转换的规则(对于对象,其会被ToPrimitive转换成基本类型,所以最终还是要应用基本类型转换规则)
1.+操作符
+操作符的两边有至少一个string类型变量时,两边的变量都会被隐式转换为字符串;其他情况下两边的变量都会被转换为数字。
1+'23' //'123'
1+false //1
1+Symbol() // Cannot convert a Symbol value to a number
'1'+false //'1false'
false+true // 1
2.-、*、\操作符
NaN也是一个数字
1*‘23’ //23
1*false //0
1/'aa //NaN
3.==操作符
操作符两边的值都尽量转成number
3 == true //false 3转为number为3,true转为number为1
‘0’ == false //true ‘0’转为number为0 false转为number为0
‘0’ == 0 //true ‘0’转为number为0
4.>和<比较符
如果两边都是字符串,则会比较字符顺序
'ca'<'bd' //false
'a' < 'b' //true
其他情况下,转换为数字再比较:
'12' < 13 //true
false > -1 //true
以上都是基本类型的隐式转换,而对象会被ToPrimitive转换为基本类型再进行转换:
let a = {}
a > 2 //false
对比过程如下:
a.valueOf() //{} ToPrimitive默认type为number,所以先valueOf,结果还是个对象
a.toString() // '[object Object]'
Number(a.toString()) //NaN 根据上面<和>操作符的规则,要转换成数字
NaN > 2 //false 得出比较结果
再或者
let a = {name:'Jack'}
let b = {age:18}
a+b //"[object Object][object Object]"
运算过程如下:
a.valueOf() // {},上⾯提到过,ToPrimitive默认type为number,所以先
valueOf,结果还是个对象,下⼀步
a.toString() // "[object Object]"
b.valueOf() // 同理
b.toString() // "[object Object]"
a + b // "[object Object][object Object]"
根据ES5规范,如果某个操作数是字符串或者能够通过以下步骤转换为字符串的话,+将进行拼接操作。如果其中一个操作数是对象(包括数组),则首先对其调用ToPrimitive抽象操作,该抽象操作再调用[[DefaultValue]],以数字作为上下文。如果不能转换为字符串,则会将其转换为数字类型来进行计算。
简单来说就是,如果+的其中一个操作数是字符串(或者通过以上步骤最终得到了字符串),则执行字符串拼接,否则就执行数字加法。
那么对于除了加法的运算符来说,只要其中一方是数字,那么另一方就会被转为数字。
JavaScript中Number.MAX_SAFE_INTEGER表示最大安全数字,计算结果是9007199254740991,即在这个数范围内不会出现精度丢失(小数除外)。但是一旦超过这个范围,JavaScript就会出现计算不准确的情况,这在大数计算的时候,不得不依靠一些第三方库进行解决,因此官方提出了BigInt来解决此问题。
扩展运算符:
let outObj = {
inObj:{a:1,b:2}
}
let newObj = {...outObj}
newObj.inObj.a = 2
console.log(outObj); //{ inObj: { a: 2, b: 2 } }
Object.assign()
let outObj = {
inObj:{a:1,b:2}
}
let newObj = Object.assign({},outObj)
newObj.inObj.a = 2
console.log(outObj); //{ inObj: { a: 2, b: 2 } }
可以看出,两个都是浅拷贝。