JS 裡為什麼會有 this

1、需求

假設我們有一個對象

var person = {
    name: 'Frank',
    age: 18,
    phone: '13812345678',
    sayHi: function(){
      // 待補充
    },
    sayBye: function(){
      // 待補充
    }
}

這個 person 對象有 name age 屬性,還有一個 sayHi 方法,現在的需求是:

調用 person.sayHi(...) ,打印出「你好,我是 Frank,今年 18 歲」。
調用 person.sayBuy(...) ,打印出「再見,記得我叫 Frank 哦,想約我的話打電話給我,我的電話是 13812345678」

求就是這麼簡單,通過達成這個需求,我們就能理解 this 的本質。

2、方案

var person = {
    ...
    sayHi: function(name, age){
      console.log('你好,我是 ${name},今年 ${age} 歲')
    },
    sayBye: function(name, phone){
      console.log('再見,記得我叫 ${name} 哦,想約我的話打電話給我,我的電話是 ${phone}')
    }
}

調用方式是

person.sayHi(person.name, person.age)
person.sayBye(person.name, person.phone)

別急,我知道這代碼很傻,接下來改進。

3、第一次改進

上面方法中,每次都要在調用的時候自行選擇 person.name 作為參數,真的很傻,不如直接傳入一個 person代碼如下:

var person = {
    ...
    sayHi: function(self){
      console.log('你好,我是 ${self.name},今年 ${self.age} 歲')
    },
    sayBye: function(self){
      console.log('再見,記得我叫 ${self.name} 哦,想約我的話打電話給我,我的電話是 ${self.phone}')
    }
}

調用方式是

person.sayHi(person)
person.sayBye(person)

稍微好一點瞭,但是這代碼依然很傻。
為什麼不能把參數裡的 person 省掉,變成 person.sayHi() 就好瞭。

4、加糖

開發者最想要的調用方式是 person.sayHi()那麼問題來瞭,如果 person.sayHi() 沒有實參,person.sayHi 函數是如何接收到 person 的呢?

  • 方法1:依然把第一個參數 self 當做 person,這樣形參就會永遠比實參多出一個 self
  • 方法2:隱藏 self,然後用關鍵字 this 來訪問 self

JS 之父選擇瞭方法2,用 this 訪問 selfPython 之父選擇瞭方法1,留下 self 作為第一個參數。

過程如下:

// 用 this 之前:
sayHi: function(self){
    console.log('你好,我是 ${self.name},今年 ${self.age} 歲')
}
// 用 this 之後:
sayHi: function(){
    // this 就是 self
    console.log('你好,我是 ${this.name},今年 ${this.age} 歲')
}

5、費解

用瞭 this 之後,完整代碼如下:

var person = {
    name: 'Frank',
    age: 18,
    phone: '13812345678',
    sayHi: function(){
      console.log('你好,我是 ${this.name},今年 ${this.age} 歲')
    },
    sayBye: function(){
      console.log('再見,記得我叫 ${this.name} 哦,想約我的話打電話給我,我的電話是 ${this.phone}')
    }
}

現在輪到新手疑惑瞭,這個 this 到底是個啥玩意兒?從哪來的呀?

實際this 是隱藏的第一個形參。在你調用 person.sayHi() 時,這個 person 會「變成」 this

6、存在問題

很多 JS 高手不屑於用 this,覺得 this 不夠單純。所以 JS 之父給高手們準備瞭無糖的 .call 方法。

person.sayHi.call(person) 就等價於 person.sayHi()

.call 的第一個參數就是顯式的 person,沒有任何語法糖。

所以高手一般用 obj.fn.call(null,1,2,3) 來手動禁用 this

這樣一來 person.sayHi.call 的參數其實可以是任何對象。

也就是說 person.sayHi 雖然是 person 的方法,但是是可以調用在任何對象上的。

7、對象與函數

JS 沒有類沒有方法,隻有對象和函數。

JS 加瞭 class 關鍵字之後,勉強弄出來一個假的類。

this 是連接對象和函數的橋梁。

相比於 JS,我更喜歡 Python 的方式,不使用 this 關鍵字,而是使用 self 形參,更易懂。

到此這篇關於JS 裡為什麼會有 this的文章就介紹到這瞭,更多相關JS 裡為什麼會有 this內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!

推薦閱讀: