一次弄懂Javascript隱式轉換
阿新 • • 發佈:2020-06-29
四種轉換總覽
ToPrimitive
作用
將物件型別轉換為原始型別
語法
ToPrimitive(obj,type)
type不同值的說明
type為string:
1.先呼叫obj的toString方法,如果為原始值,則return,否則進行第2步
2.呼叫obj的valueOf方法,如果為原始值,則return,否則進行第3步
3.丟擲TypeError 異常
複製程式碼
type為number:
1.先呼叫obj的valueOf方法,如果為原始值,則return,否則進行第2步
2.呼叫obj的toString方法,如果為原始值,則return,否則第3步
3.丟擲TypeError 異常
複製程式碼
type引數為空
1.該物件為Date,則type被設定為String
2.否則,type被設定為Number
複製程式碼
ToPrimitive總結
ToPrimitive轉成何種原始型別,取決於type,type引數可選。
若指定,則按照指定型別轉換。
若不指定,預設根據實用情況分兩種情況,Date為string,其餘物件為number。
複製程式碼
ToString
將其他型別轉換為字串型別
規則(文字)
null:轉為"null"
undefined:轉為"undefined"
布林型別:true和false分別被轉為"true"和"false"
數字型別:轉為數字的字串形式,如10轉為"10"
陣列:轉為以","連線的字串,空陣列[]轉為空字串,陣列中的null或undefined,會被當做空字串處理
普通物件:轉為字串相當於直接使用Object.prototype.toString(),返回"[object Object]"
複製程式碼
規則(表格)
ToNumber
將其他型別轉換為數字型別
null: 轉為0
undefined:轉為NaN
字串:如果是純數字形式,則轉為對應的數字,空字元轉為0,否則一律按轉換失敗處理,轉為NaN
布林:true和false被轉為1和0
陣列:陣列先被轉為原始型別,然後在根據轉換後的原始型別按照上面的規則處理
物件:同陣列的處理方式
複製程式碼
規則(表格)
ToBoolean
將其他型別轉換為布林型別
null、undefined、0、NaN、””轉為false
其餘轉為 true
複製程式碼
規則(表格)
==運算子規則
比較運算 x==y,其中 x 和 y 是值,返回 true 或者 false。這樣的比較按如下方式進行
1、若 Type(x) 與 Type(y) 相同, 則
1* 若 Type(x) 為 Undefined, 返回 true。
2* 若 Type(x) 為 Null, 返回 true。
3* 若 Type(x) 為 Number, 則
(1)、若 x 為 NaN, 返回 false。
(2)、若 y 為 NaN, 返回 false。
(3)、若 x 與 y 為相等數值, 返回 true。
(4)、若 x 為 +0 且 y 為 −0, 返回 true。
(5)、若 x 為 −0 且 y 為 +0, 返回 true。
(6)、返回 false。
4* 若 Type(x) 為 String,則當 x 和 y 為完全相同的字元序列(長度相等且相同字元在相同位置)時返回 true。 否則, 返回 false。
5* 若 Type(x) 為 Boolean,當 x 和 y 為同為 true 或者同為 false 時返回 true。 否則, 返回 false。
6* 當 x 和 y 為引用同一物件時返回 true。否則,返回 false。
2、若 x 為 null 且 y 為 undefined, 返回 true。
3、若 x 為 undefined 且 y 為 null, 返回 true。
4、若 Type(x) 為 Number 且 Type(y) 為 String,返回比較 x == ToNumber(y) 的結果。
5、若 Type(x) 為 String 且 Type(y) 為 Number,返回比較 ToNumber(x) == y 的結果。
6、若 Type(x) 為 Boolean, 返回比較 ToNumber(x) == y 的結果。
7、若 Type(y) 為 Boolean, 返回比較 x == ToNumber(y) 的結果。
8、若 Type(x) 為 String 或 Number,且 Type(y) 為 Object,返回比較 x == ToPrimitive(y) 的結果。
9、若 Type(x) 為 Object 且 Type(y) 為 String 或 Number, 返回比較 ToPrimitive(x) == y 的結果。
10、返回 false。
複製程式碼
例題解析
a 為什麼值時,控制檯能輸出Hello world?
a = ? //
if(a == 1 && a == 2 && a == 3){
console.log("Hello world")
}
複製程式碼
解法1
利用物件在和原始型別的值比較是預設呼叫ToPrimitive方法裡的ValueOf方法
var a = {
i: 1, valueOf() {
return this.i++;
}
}
if (a == 1 && a == 2 && a == 3) {
console.log("Hello world");
}
複製程式碼
1、在判斷a == 1時,因為a為非原始型別,所以需要先呼叫ToPrimitive方法,呼叫valueOf方法。
2、返回this.i值為1,並將i自加1,返回的1與等式右邊的1進行比較返回true。
3、後面的操作同理
複製程式碼
解法2
利用物件在和原始型別的值比較是預設呼叫ToPrimitive方法裡的ToString方法
return
this.i++;
}
}
if (a == 1 && a == 2 && a == 3) {
console.log("Hello world");
}
複製程式碼
1、在判斷a == 1時,因為a為非原始型別,所以需要先呼叫ToPrimitive方法,呼叫valueOf方法,返回自身
2、繼續呼叫toString方法,返回this.i的值為1,並將i自加1,返回的1與等式右邊的1進行比較返回true。
3、後面的操作同理
複製程式碼
解法3
利用物件在和原始型別的值比較是預設呼叫ToPrimitive方法裡的ToString方法時隱式呼叫join方法
var a = [1,2,3];
a.join = a.shift;
if (a == 1 && a == 2 && a == 3) {
console.log("Hello world");
}
複製程式碼
1、在判斷a == 1時,因為a為非原始型別,所以需要先呼叫ToPrimitive方法,呼叫valueOf方法,返回自身
2、繼續呼叫toString方法,toString方法預設呼叫join方法
3、而物件a上的join方法被重寫,變成shift方法,因此執行shift方法返回被刪除的1,陣列變成[2,3]
4、後面的操作同理
複製程式碼
其他解法
var val = 0;
Object.defineProperty(window,'a',{
get: function() {
return ++val;
}
});
// ---------------------------------
let a={
reg: /\d/g, valueOf(){
return this.reg.exec(123)[0]
}
}
複製程式碼
最後兩個解法不屬於隱式轉換,所以不再展開
複製程式碼
課後習題
null >0 // false
null == 0// false
null >= 0 // true
[] == ![] // true
[] == 0 // true
[2]== 2 // true
['0'] == false // true
'0' == false // true
[] == false // true
[null] == 0 // true
null == 0 // false
[null] == false // true
null == false // false
[undefined] == false // true
undefined == false // false
複製程式碼
null:轉為"null"
undefined:轉為"undefined"
布林型別:true和false分別被轉為"true"和"false"
數字型別:轉為數字的字串形式,如10轉為"10"
陣列:轉為以","連線的字串,空陣列[]轉為空字串,陣列中的null或undefined,會被當做空字串處理
普通物件:轉為字串相當於直接使用Object.prototype.toString(),返回"[object Object]"
複製程式碼
null: 轉為0
undefined:轉為NaN
字串:如果是純數字形式,則轉為對應的數字,空字元轉為0,否則一律按轉換失敗處理,轉為NaN
布林:true和false被轉為1和0
陣列:陣列先被轉為原始型別,然後在根據轉換後的原始型別按照上面的規則處理
物件:同陣列的處理方式
複製程式碼
規則(表格)
ToBoolean
將其他型別轉換為布林型別
null、undefined、0、NaN、””轉為false
其餘轉為 true
複製程式碼
規則(表格)
==運算子規則
比較運算 x==y,其中 x 和 y 是值,返回 true 或者 false。這樣的比較按如下方式進行
1、若 Type(x) 與 Type(y) 相同, 則
1* 若 Type(x) 為 Undefined, 返回 true。
2* 若 Type(x) 為 Null, 返回 true。
3* 若 Type(x) 為 Number, 則
(1)、若 x 為 NaN, 返回 false。
(2)、若 y 為 NaN, 返回 false。
(3)、若 x 與 y 為相等數值, 返回 true。
(4)、若 x 為 +0 且 y 為 −0, 返回 true。
(5)、若 x 為 −0 且 y 為 +0, 返回 true。
(6)、返回 false。
4* 若 Type(x) 為 String,則當 x 和 y 為完全相同的字元序列(長度相等且相同字元在相同位置)時返回 true。 否則, 返回 false。
5* 若 Type(x) 為 Boolean,當 x 和 y 為同為 true 或者同為 false 時返回 true。 否則, 返回 false。
6* 當 x 和 y 為引用同一物件時返回 true。否則,返回 false。
2、若 x 為 null 且 y 為 undefined, 返回 true。
3、若 x 為 undefined 且 y 為 null, 返回 true。
4、若 Type(x) 為 Number 且 Type(y) 為 String,返回比較 x == ToNumber(y) 的結果。
5、若 Type(x) 為 String 且 Type(y) 為 Number,返回比較 ToNumber(x) == y 的結果。
6、若 Type(x) 為 Boolean, 返回比較 ToNumber(x) == y 的結果。
7、若 Type(y) 為 Boolean, 返回比較 x == ToNumber(y) 的結果。
8、若 Type(x) 為 String 或 Number,且 Type(y) 為 Object,返回比較 x == ToPrimitive(y) 的結果。
9、若 Type(x) 為 Object 且 Type(y) 為 String 或 Number, 返回比較 ToPrimitive(x) == y 的結果。
10、返回 false。
複製程式碼
例題解析
a 為什麼值時,控制檯能輸出Hello world?
a = ? //
if(a == 1 && a == 2 && a == 3){
console.log("Hello world")
}
複製程式碼
解法1
利用物件在和原始型別的值比較是預設呼叫ToPrimitive方法裡的ValueOf方法
var a = {
i: 1, valueOf() {
return this.i++;
}
}
if (a == 1 && a == 2 && a == 3) {
console.log("Hello world");
}
複製程式碼
1、在判斷a == 1時,因為a為非原始型別,所以需要先呼叫ToPrimitive方法,呼叫valueOf方法。
2、返回this.i值為1,並將i自加1,返回的1與等式右邊的1進行比較返回true。
3、後面的操作同理
複製程式碼
解法2
利用物件在和原始型別的值比較是預設呼叫ToPrimitive方法裡的ToString方法
return
this.i++;
}
}
if (a == 1 && a == 2 && a == 3) {
console.log("Hello world");
}
複製程式碼
null、undefined、0、NaN、””轉為false
其餘轉為 true
複製程式碼
規則(表格)
==運算子規則
比較運算 x==y,其中 x 和 y 是值,返回 true 或者 false。這樣的比較按如下方式進行
1、若 Type(x) 與 Type(y) 相同, 則
1* 若 Type(x) 為 Undefined, 返回 true。
2* 若 Type(x) 為 Null, 返回 true。
3* 若 Type(x) 為 Number, 則
(1)、若 x 為 NaN, 返回 false。
(2)、若 y 為 NaN, 返回 false。
(3)、若 x 與 y 為相等數值, 返回 true。
(4)、若 x 為 +0 且 y 為 −0, 返回 true。
(5)、若 x 為 −0 且 y 為 +0, 返回 true。
(6)、返回 false。
4* 若 Type(x) 為 String,則當 x 和 y 為完全相同的字元序列(長度相等且相同字元在相同位置)時返回 true。 否則, 返回 false。
5* 若 Type(x) 為 Boolean,當 x 和 y 為同為 true 或者同為 false 時返回 true。 否則, 返回 false。
6* 當 x 和 y 為引用同一物件時返回 true。否則,返回 false。
2、若 x 為 null 且 y 為 undefined, 返回 true。
3、若 x 為 undefined 且 y 為 null, 返回 true。
4、若 Type(x) 為 Number 且 Type(y) 為 String,返回比較 x == ToNumber(y) 的結果。
5、若 Type(x) 為 String 且 Type(y) 為 Number,返回比較 ToNumber(x) == y 的結果。
6、若 Type(x) 為 Boolean, 返回比較 ToNumber(x) == y 的結果。
7、若 Type(y) 為 Boolean, 返回比較 x == ToNumber(y) 的結果。
8、若 Type(x) 為 String 或 Number,且 Type(y) 為 Object,返回比較 x == ToPrimitive(y) 的結果。
9、若 Type(x) 為 Object 且 Type(y) 為 String 或 Number, 返回比較 ToPrimitive(x) == y 的結果。
10、返回 false。
複製程式碼
例題解析
a 為什麼值時,控制檯能輸出Hello world?
a = ? //
if(a == 1 && a == 2 && a == 3){
console.log("Hello world")
}
複製程式碼
解法1
利用物件在和原始型別的值比較是預設呼叫ToPrimitive方法裡的ValueOf方法
var a = {
i: 1, valueOf() {
return this.i++;
}
}
if (a == 1 && a == 2 && a == 3) {
console.log("Hello world");
}
複製程式碼
1、在判斷a == 1時,因為a為非原始型別,所以需要先呼叫ToPrimitive方法,呼叫valueOf方法。
2、返回this.i值為1,並將i自加1,返回的1與等式右邊的1進行比較返回true。
3、後面的操作同理
複製程式碼
解法2
利用物件在和原始型別的值比較是預設呼叫ToPrimitive方法裡的ToString方法
return
this.i++;
}
}
if (a == 1 && a == 2 && a == 3) {
console.log("Hello world");
}
比較運算 x==y,其中 x 和 y 是值,返回 true 或者 false。這樣的比較按如下方式進行
1、若 Type(x) 與 Type(y) 相同, 則
1* 若 Type(x) 為 Undefined, 返回 true。
2* 若 Type(x) 為 Null, 返回 true。
3* 若 Type(x) 為 Number, 則
(1)、若 x 為 NaN, 返回 false。
(2)、若 y 為 NaN, 返回 false。
(3)、若 x 與 y 為相等數值, 返回 true。
(4)、若 x 為 +0 且 y 為 −0, 返回 true。
(5)、若 x 為 −0 且 y 為 +0, 返回 true。
(6)、返回 false。
4* 若 Type(x) 為 String,則當 x 和 y 為完全相同的字元序列(長度相等且相同字元在相同位置)時返回 true。 否則, 返回 false。
5* 若 Type(x) 為 Boolean,當 x 和 y 為同為 true 或者同為 false 時返回 true。 否則, 返回 false。
6* 當 x 和 y 為引用同一物件時返回 true。否則,返回 false。
2、若 x 為 null 且 y 為 undefined, 返回 true。
3、若 x 為 undefined 且 y 為 null, 返回 true。
4、若 Type(x) 為 Number 且 Type(y) 為 String,返回比較 x == ToNumber(y) 的結果。
5、若 Type(x) 為 String 且 Type(y) 為 Number,返回比較 ToNumber(x) == y 的結果。
6、若 Type(x) 為 Boolean, 返回比較 ToNumber(x) == y 的結果。
7、若 Type(y) 為 Boolean, 返回比較 x == ToNumber(y) 的結果。
8、若 Type(x) 為 String 或 Number,且 Type(y) 為 Object,返回比較 x == ToPrimitive(y) 的結果。
9、若 Type(x) 為 Object 且 Type(y) 為 String 或 Number, 返回比較 ToPrimitive(x) == y 的結果。
10、返回 false。
複製程式碼
a = ? //
if(a == 1 && a == 2 && a == 3){
console.log("Hello world")
}
複製程式碼
var a = {
i: 1, valueOf() {
return this.i++;
}
}
if (a == 1 && a == 2 && a == 3) {
console.log("Hello world");
}
複製程式碼
1、在判斷a == 1時,因為a為非原始型別,所以需要先呼叫ToPrimitive方法,呼叫valueOf方法。
2、返回this.i值為1,並將i自加1,返回的1與等式右邊的1進行比較返回true。
3、後面的操作同理
複製程式碼
return
1、在判斷a == 1時,因為a為非原始型別,所以需要先呼叫ToPrimitive方法,呼叫valueOf方法,返回自身
2、繼續呼叫toString方法,返回this.i的值為1,並將i自加1,返回的1與等式右邊的1進行比較返回true。
3、後面的操作同理
複製程式碼
解法3
利用物件在和原始型別的值比較是預設呼叫ToPrimitive方法裡的ToString方法時隱式呼叫join方法
var a = [1,2,3];
a.join = a.shift;
if (a == 1 && a == 2 && a == 3) {
console.log("Hello world");
}
複製程式碼
1、在判斷a == 1時,因為a為非原始型別,所以需要先呼叫ToPrimitive方法,呼叫valueOf方法,返回自身
2、繼續呼叫toString方法,toString方法預設呼叫join方法
3、而物件a上的join方法被重寫,變成shift方法,因此執行shift方法返回被刪除的1,陣列變成[2,3]
4、後面的操作同理
複製程式碼
其他解法
var val = 0;
Object.defineProperty(window,'a',{
get: function() {
return ++val;
}
});
// ---------------------------------
let a={
reg: /\d/g, valueOf(){
return this.reg.exec(123)[0]
}
}
複製程式碼
最後兩個解法不屬於隱式轉換,所以不再展開
複製程式碼
課後習題
null >0 // false
null == 0// false
null >= 0 // true
[] == ![] // true
[] == 0 // true
[2]== 2 // true
['0'] == false // true
'0' == false // true
[] == false // true
[null] == 0 // true
null == 0 // false
[null] == false // true
null == false // false
[undefined] == false // true
undefined == false // false
複製程式碼