js型別轉換的各種玩法

2021-09-12 17:36:33 字數 4475 閱讀 9576

前言

對於object和number、string、boolean之間的轉換關係

toprimitive是指轉換為js內部的原始值,如果是非原始值則轉為原始值,呼叫valueof()和tostring()來實現。valueof返回物件的值:在控制台,當你定義乙個物件按回車,控制台列印的是object,tostring()返回物件轉字串的形式,列印的是"[object object]"

1.一些例子

在瀏覽器控制台輸入一些各種運算子的組合,會出現一些有意思的結果:

! //false;

+ // 0

+! // 0

+ // ""

{}+{}//"[object object][object object]"

{}+//0

+1 // 1

+{}//"[object object]"

+!//"false"

{}+//0

!+ // "false"

''+{} //"[object object]"

{}+'' //0

["map"]+ //"function map() "

["a"]+ // "undefined"

+ // "undefined"

+!!+ //"1"

+!! //1

1-{} //nan

1- //1

true-1 //0

{}-1 //-1

==! //true

2.從==!開始

我們知道,!=,主要是因為他們是引用型別,記憶體位址不同所以不相等。那麼為什麼加了乙個!就能劃上等於號了

符號的優先度

可以參考mdn上的這個彙總**: 可以看見,==!這個情況下先判斷!再判斷= 給取反,會是布林值,的取反的布林值就是false

2.1 的反就是false?

常見的一些轉換:

非布林型別轉布林型別:undefined、null 、0、±0、nan、0長度的字串=》false,物件=》true 非數字型別轉數字型別:undefined=》nan,null=》0,true=》1,false=》0,字串:字串數字直接轉數字型別、字串非數字=》nan

回到==!的問題上,也是物件型別(typeof == "object"),轉為布林型別的!就是false

2.2 等號兩邊對比

我們知道,在比較型別的時候,先會進行各種各樣的型別轉換。 從開頭的**可以看見,他們比較的時候都是先轉換為數字型別。右邊是布林值false,左邊為乙個空陣列物件,對於左邊,先進行toprimitive操作,先執行valueof()返回的是,非原始型別,再.tostring(),返回的是"",那toprimitive操作之後,結果就是""了 最後,左邊""和右邊false對比,他們再轉換為數字,就是0 == 0的問題了

3.更多玩法

3.1 間接獲取陣列方法

我們知道,陣列有自己的一套方法,比如var arr = [1,2];arr.push(1),我們可以寫成[1,2].push(1),還可以寫成[1,2]['push'](1),那麼前面丟擲的問題就解決了

['push'](1) //[1]

["map"] //function map()

["map"]+ // "function map() "

3.2 間接進行下標操作

3.2.1數字的獲取

我們可以通過型別轉換,獲得0和1兩個數字,既然能得到這兩個數字,那麼也可以得到其他的一切數字了: + === 0; +!! === 1那麼,+!!+!! ===2,+((+!)+(+!!)++(+!))===10

那麼10-1=9也就來了:+((+!)+(+!!)++(+!))-!! ===9簡直就是無所不能

3.2.2 字串下標

(!+)[+] //"f"

(!+)[+!!] // "a"

(!+)是"false",其實(!+)[+]就相當於"false"[0],第乙個字母,就是f 我們就可以從上面的那些獲得單詞的字串獲得其中的字母了,比如:(!+)[+!!+!!+!!] +(+{})[+!!+!!]

掌握基本套路後,我們可以隨心所欲發揮,在瀏覽器的控制台輸入一些符號的組合,然後回車看一下我們寫的「密碼」會轉換成什麼

( + )[(+!! +  +  + +! ) >> +!!] +

$$('*')[~~].nodename[- ~ -+~] +

(this + )[+!!+ + + - !!{} - !!{}] +

(+!)[+!!{} << +!! -~] +

({}+{})[+!! -~]

4. 兩個面試題

曾經遇到兩個這種型別的面試題:

4.1(a==1 && a==2 && a==3)能不能為true

(a==1 && a==2 && a==3)或者(a===1 && a===2 && a===3)能不能為true? 事實上是可以的,就是因為在==比較的情況下,會進行型別的隱式轉換。前面已經說過,如果引數不是date物件的例項,就會進行型別轉換,先valueofobj.tostring()所以,我們只要改變原生的valueof或者tostring方法就可以達到效果:

var a = 

};var eq = (a==1 && a==2 && a==3);

console.log(eq);

//或者改寫他的tostring方法

var num = 0;

function.prototype.tostring = function()

function a(){}

//還可以改寫es6的symbol型別的top的方法

var a = }) (0)};

每一次進行等號的比較,就會呼叫一次valueof方法,自增1,所以能成立。 另外,減法也是同理:

var a = 

};var res = (a==3 && a==2 && a==1);

console.log(res);

另外,如果沒有型別轉換,是 === 的比較,還是可以的。 在vue原始碼實現雙向資料繫結中,就利用了defineproperty方法進行觀察資料被改變的時候,觸發set。 每一次訪問物件中的某乙個屬性的時候,就會呼叫這個方法定義的物件裡面的get方法。每一次改變物件屬性的值,就會訪問set方法 在這裡,我們自己定義自己的get方法:

var b = 1

object.defineproperty(window, 'a',

})var s = (a===1 && a===2 && a === 3 )

console.log(s)

每一次訪問a屬性,a的屬性值就會+1,當然還是交換位置就不能為true了

4.2 完善cash列印三個101

要求只能在class裡面增加**:

class cash {}

const a = new cash(1)

const b = new cash(100)

console.log(`$,$,$`) // 101,101,101

首先,三個輸出結果是以隱式轉換的形式出現的,這是關鍵之處。 a和b都是new出來的物件,由new cash(a+b)可以看出建構函式傳入的也是兩個cash的例項物件。那麼new出來的結果肯定不是簡簡單單的乙個object,不然就是被轉換成'[object object]',但是你又不得不以object型別出現,那就只能魔改隱式轉換用到的tostring和valueof

class cash 

}add ($)

tostring ()

static add (v1, v2)

}

最後

然而,實際專案中兩個資料作比較的時候,我們盡量不要寫甚至完全不要寫兩個等號,應該寫三個等號,而且js也慢慢有向強型別過渡的趨勢。

js型別轉換的各種玩法

前言 對於object和number string boolean之間的轉換關係 toprimitive是指轉換為js內部的原始值,如果是非原始值則轉為原始值,呼叫valueof 和tostring 來實現。valueof返回物件的值 在控制台,當你定義乙個物件按回車,控制台列印的是object,t...

js型別轉換的各種玩法

前言 對於object和number string boolean之間的轉換關係 toprimitive是指轉換為js內部的原始值,如果是非原始值則轉為原始值,呼叫valueof 和tostring 來實現。valueof返回物件的值 在控制台,當你定義乙個物件按回車,控制台列印的是object,t...

各種字元型別的轉換,各種字元編碼轉換

pragma once 字元轉換成byte static byte char2byte char c else if a c c f else if a c c f else 組合位元組 static byte makebyte char hichar,char lochar 16進製制字元轉換成字...