JavaScript:(a==1 && a==2 && a==3)能輸出ture麼?

若是你能確切的答出能夠,那恭喜你,你能夠繞道了

前言

有人會說,這個問題好奇葩,放在別的語言裏,這要是能輸出true,估計是見鬼了,可是你別說,放在js中好真有可能。最近在一我的的推特上提了一個問題:git

  • 問題:Can (a==1 && a==2 && a==3) ever evaluate to true?
  • 答案:yes

在這篇文章中,我將解釋這段代碼的原理:github

const a = {
  num: 0,
  valueOf: function() {
    return this.num += 1
  }
};
const equality = (a==1 && a==2 && a==3);
console.log(equality); // true

你能夠打開chorme瀏覽器,而後打開開發者模式,在console中輸入這段代碼,你就能夠看到輸出結果([windows]: Ctrl + Shift + J [mac]: Cmd + Opt + J)windows

有什麼竅門呢?

其實也沒有,能有的就是js中的兩個概念:瀏覽器

  • 隱式轉換
  • object的valueOf函數

隱式轉換

注意:這題裏面咱們用的是==而不是===,在js中==表明的是等於而不是全等,那麼就存在變量的隱式轉化問題。這就意味着結果會比咱們所指望的更多的可能性。對於js的隱式轉化,真的有不少文章,我推薦一下如下幾篇博客,若是你想要了解,能夠點進去:函數

推薦博客測試

valueOf

JavaScript提供了一種將對象轉化爲原始值的方法:Object.prototype.valueOf(),默認狀況下,返回正在被調用的對象。this

咱們舉個例子:lua

const a = {
  num: 0
}

咱們能夠對上述對象使用valueOf方法,他會返回一個對象。spa

a.valueOf();
// {num: 0}

是否是很酷,咱們能夠用typeOf來檢測一下這個輸出結果的類型:prototype

typeof a.valueOf();
// "object"

爲了讓valueOf能夠更方便將一個對象轉化成原始值,咱們能夠重寫他,換種說法就是咱們能夠經過valueOf來返回一個字符串、數字、布爾值等來代替一個對象,咱們能夠看如下代碼:

a.valueOf = function() {
  return this.num;
}

咱們已經重寫了原生的valueOf()方法,當咱們調用valueOf的時候,他會返回a.num。那咱們如今運行如下:

a.valueOf();
// 0

咱們獲得0了,這很合理,由於0就是賦給a.num的值。那咱們能夠來作幾個測試:

typeof a.valueOf();
// "number"

a.num == a.valueOf()
// true

很好,但爲何這個很重要呢?

這很重要,由於當你兩種不一樣類型的遇到相等操做符的時候,js會對其進行類型轉化——它企圖將操做數的類型轉化爲相似的。

在咱們的問題中:(a==1 && a==2 && a==3)JavaScript會企圖將對象轉化成數字的類型,進行比較。當要轉化的是一個Object的時候,JavaScript會調用valueOf()方法。

自從咱們改變了valueOf()方法以後,咱們能不能作到如下幾點呢:

a == 0

// true

咱們作到了,異常輕鬆。

如今咱們須要作的的一點是:當咱們每次去調用a的值的時候,能改變它。

幸運的是,在JavaScript中有+=符號。

+=這個運算符能夠輕鬆的去改變一個的值,咱們能夠舉個簡單的例子:

let b = 1
console.log(b+=1); // 2
console.log(b+=1); // 3
console.log(b+=1); // 4

正如你所見的,咱們每次使用加法賦值運算符,可讓咱們的變量增長。

因此咱們能夠將這個觀念用到valueOf()中。

a.valueOf = function() {
  return this.num += 1;
}

當咱們每次調用valueOf的時候,他會將變量增長1返回給咱們。

隨着這個改變,咱們來運行下面的代碼:

const equality = (a==1 && a==2 && a==3);
console.log(equality); // true

這就是它的工做原理。

記住下面兩點:

  • 使用相等操做符,js會作強制類型轉化
  • 咱們的對象每次調用valueOf()它的值會增長1

因此比較的時候咱們每次都能獲得true。

  • 補充第二點的運算過程
a                     == 1   -> 
a.valueOf()           == 1   -> 
a.num += 1            == 1   -> 
0     += 1            == 1   ->
1                     == 1   -> true
a                     == 2   -> 
a.valueOf()           == 2   -> 
a.num += 1            == 2   -> 
1     += 1            == 2   ->
2                     == 2   -> true
a                     == 3   -> 
a.valueOf()           == 3   -> 
a.num += 1            == 3   -> 
2     += 1            == 3   ->
3                     == 3   -> true

總結

謝謝你觀看這個小實驗,但願你能從中學到東西,有興趣的朋友也能夠去個人github點個star,你的支持是我持續輸出的動力,謝謝!!!

相關文章
相關標籤/搜索