js隱式轉(zhuǎn)換

先看個例子

const a = {
  i: 1,
  toString: function () {
    return a.i++;
  }
}
if(a==1){
  console.log('1')
}
if(a==2){
  console.log('2')
}
if(a==3){
  console.log('3')
}

答案自己運算試試

先說說js數(shù)據(jù)類型

  1. 基礎(chǔ)類型(原始值):
    Undefined、Null、String、Number、Boolean、Symbol
  2. 復(fù)雜類型(對象值):
    Object

三種隱式轉(zhuǎn)換類型

涉及隱式轉(zhuǎn)換最多的兩個運算符 + 和 ==
+運算符即可數(shù)字相加,也可以字符串相加。
-*/ 這些運算符只會針對number類型,估轉(zhuǎn)換的結(jié)果只能是轉(zhuǎn)換成number類型。

隱式轉(zhuǎn)換中主要涉及到三種轉(zhuǎn)換:

  1. 將值轉(zhuǎn)為原始值(基礎(chǔ)類型的值),ToPrimitive()
  2. 將值轉(zhuǎn)為數(shù)字,ToNumber()
  3. 將值轉(zhuǎn)為字符串,ToString()

通過ToPrimitive將值轉(zhuǎn)換為原始值

ToPrimitive(input,PreferredType?)
input是要轉(zhuǎn)換的值,PreferredType是可選參數(shù),可以是Number或String類型。他只是一個轉(zhuǎn)換標(biāo)志,轉(zhuǎn)化后的結(jié)果并不一定是這個參數(shù)所指的類型,但是轉(zhuǎn)換結(jié)果一定是一個原始值或者報錯。

  • 如果PreferredType被編輯為Number,則會進(jìn)行下面的操作流程來轉(zhuǎn)換輸入的值。
1. 如果輸入的值已經(jīng)是一個原始值,則直接返回它。
2. 否則,如果輸入的值是一個對象,則調(diào)用該對象的valueOf()方法,如果valueOf()方法的返回值是一個原始值,則返回這個原始值。
3. 否則,調(diào)用這個對象的toString()方法,如果toString()方法返回的是一個原始值,則返回這個原始值。
4. 否則,拋出TypeError異常。
  • 如果PreferredType被標(biāo)記為String,則會進(jìn)行下面的操作流程來轉(zhuǎn)換輸入的值。
1. 如果輸入的值已經(jīng)是一個原始值,則直接返回它。
2. 否則,調(diào)用這個對象的toString()方法,如果toString()方法返回的是一個原始值,則返回這個原始值。
3. 否則,如果輸入的值是一個對象,則調(diào)用該對象的valueOf()方法,如果valueOf()方法的返回值是一個原始值,則返回這個原始值。
4. 否則,拋出TypeError異常。

既然PreferredType是可選參數(shù),那么如果沒有這個參數(shù)時,怎么轉(zhuǎn)換?規(guī)則如下:

1. 該對象為Date類型,則PreferredType被設(shè)置為String
2. 否則,PreferredType被設(shè)置為Number

valueOf方法和toString方法解析

Object.prototype具有valueOf和toString方法,而Object.prototype是所有對象原型鏈頂層原型,所有對象都會繼承該原型的方法,故任何對象都會有valueOf和toString方法。

valueOf函數(shù)對js的常見內(nèi)置對象轉(zhuǎn)換結(jié)果:

  1. Number、Boolean、String這三種構(gòu)造函數(shù)生成的基礎(chǔ)值的對象形式,通過valueOf轉(zhuǎn)換后變成相應(yīng)的原始值。
var num = new Number('123');
num.valueOf();  //123

var str = new String('123');
str.valueOf(); //'123'

var bool = new Boolean('fa');
bool.valueOf(); // true
  1. Date這種特殊的對象,其原型Date.prototype上內(nèi)置的vauleOf函數(shù)將日期轉(zhuǎn)換為毫秒的形式的數(shù)值。
var a = new Date();
a.valueOf();  //1608262149351
  1. 除此之外返回的都為this,即對象本身:
var a = new Array();
a.valueOf()  //[]

var b = new Object({});
b.valueOf()  //{}

toString函數(shù)對js的常見內(nèi)置對象轉(zhuǎn)換結(jié)果:

var num = new Number('123sd');  //若為純數(shù)字,則為數(shù)字字符串
num.toString(); //'NaN'

var str = new String('12df')
str.toString();  //12df

var bool = new Boolean('fd');
bool.toString(); // 'true'

var arr = new Array(1,2);
arr.toString();  //'1,2'

var d = new Date();
d.toString();   //"Fri Dec 18 2020 11:52:17 GMT+0800 (中國標(biāo)準(zhǔn)時間)"

var func = function(){}
func.toString();  // 'function(){}'

var obj = new Object({});
obj.toString(); // "[object Object]"

練習(xí)題

({} + {} ) = ?
兩個對象的值進(jìn)行+運算符,肯定要先進(jìn)行隱式轉(zhuǎn)換為原始類型才能進(jìn)行計算。
1. 進(jìn)行ToPrimitive轉(zhuǎn)換,由于沒有指定PeferredType類型,{}會使默認(rèn)值為Number,進(jìn)行ToPrimitive(input,Number)運算。
2. 所以會執(zhí)行vauleOf方法,({}).valueOf(),返回的還是{}對象,不是原始值。
3. 繼續(xù)執(zhí)行toString方法,({}).toString(),返回"[object Object]",是原始值。
所以答案是"[object Object]" + "[object Object]" = "[object Object][object Object]"
2 * {} = ?
1、首先*運算符只能對number類型進(jìn)行運算,故第一步就是對{}進(jìn)行ToNumber類型轉(zhuǎn)換。
2、由于{}是對象類型,故先進(jìn)行原始類型轉(zhuǎn)換,ToPrimitive(input, Number)運算。
3、所以會執(zhí)行valueOf方法,({}).valueOf(),返回的還是{}對象,不是原始值。
4、繼續(xù)執(zhí)行toString方法,({}).toString(),返回"[object Object]",是原始值。
5、轉(zhuǎn)換為原始值后再進(jìn)行ToNumber運算,"[object Object]"就轉(zhuǎn)換為NaN。
故最終的結(jié)果為 2 * NaN = NaN
  1 + false
  1 + '2' + false
  1 + '2' - false
  1 - '2' + false
  1 - '2' - false
const a = {
  i: 1,
  toString: function () {
    return a.i++;
  }
}
if(a==1){
  console.log('1')
}
if(a==2){
  console.log('2')
}
if(a==3){
  console.log('3')
}

解析:

1. 當(dāng)執(zhí)行a == 1 && a == 2 && a == 3 時,會從左到右一步一步解析,首先 a ==  1,會進(jìn)行上面第9步轉(zhuǎn)換。ToPrimitive(a, Number) == 1。
2. ToPrimitive(a, Number),按照上面原始類型轉(zhuǎn)換規(guī)則,會先調(diào)用valueOf方法,a的valueOf方法繼承自O(shè)bject.prototype。返回a本身,而非原始類型,故會調(diào)用toString方法。
3. 因為toString被重寫,所以會調(diào)用重寫的toString方法,故返回1,注意這里是i++,而不是++i,它會先返回i,在將i+1。故ToPrimitive(a, Number) = 1。也就是1 == 1,此時i = 1 + 1 = 2。
(此處延伸++i 和 i++ 的區(qū)別:
  ++i,是先將值賦值給其他值之后,在進(jìn)行+1運算
  i++,是先進(jìn)行+1運算之后,將值賦值給其他值
)
4. 執(zhí)行完a == 1返回true,會執(zhí)行a == 2,同理,會調(diào)用ToPrimitive(a, Number),同上先調(diào)用valueOf方法,在調(diào)用toString方法,由于第一步,i = 2此時,ToPrimitive(a, Number) = 2, 也就是2 == 2, 此時i = 2 + 1。
5. 同上可以推導(dǎo) a == 3也返回true。故最終結(jié)果 a == 1 && a == 2 && a == 3返回true

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容