看一遍就能掌握 js 中的 this 指向

關(guān)于 this 指向私股,可能有一部分人都是模糊的茵宪,本文對(duì)常見情況下的 this 指向作出總結(jié)瞳别,讓你不再皺眉生宛。

先了解

一個(gè)基本概念:普通函數(shù)的 this 指向不是在定義的時(shí)候確定萍鲸,而是在調(diào)用的時(shí)候確定味咳。

兩個(gè)注意事項(xiàng):

  • 所有例子在瀏覽器環(huán)境(window 對(duì)象同時(shí)也是全局對(duì)象)運(yùn)行庇勃,而不是 node 環(huán)境(global)。
  • 非嚴(yán)格模式指向 Window 的對(duì)應(yīng)嚴(yán)格模式是 undefined槽驶。(Window.setTimeout 等除外责嚷,由 setTimeout 調(diào)用的代碼運(yùn)行在與所在函數(shù)完全分離的執(zhí)行環(huán)境上,即使在嚴(yán)格模式下仍然指向 Window)

接下來(lái)從一般形式函數(shù)調(diào)用掂铐、方法調(diào)用罕拂、apply 和 call 調(diào)用、箭頭函數(shù)全陨、class 等理清指向問(wèn)題爆班。

1. 一般形式函數(shù)調(diào)用

所謂一般形式函數(shù)調(diào)用就是 函數(shù)名(),this 指向全局對(duì)象辱姨。

function test() {
  console.log(this.name) // fang
}
var name = 'fang'
// let蛋济、const 聲明的變量不是 Window 屬性
const age = 1
console.log(this) // Window
console.log(this.age) // undefined
test()

2. 方法調(diào)用

一個(gè)函數(shù)被設(shè)置為對(duì)象(非全局對(duì)象)的屬性值時(shí),就是方法調(diào)用炮叶,this 指向?qū)ο笞陨怼?/p>

  • 當(dāng)函數(shù)屬于對(duì)象外層屬性的屬性值

    function test() {
      'use strict'
      console.log(this) // obj
      console.log(this.name) // fang
    }
    var name = 'wang'
    const obj = {
      name: 'fang',
      fun: test
    }
    obj.fun()
    
  • 當(dāng)函數(shù)屬于深層對(duì)象的屬性值碗旅,要明確知道它的使用者是誰(shuí)

    function test() {
      console.log(this) // obj2
      console.log(this.name) // zhang
    }
    var name = 'wang'
    const obj1 = {
      name: 'fang',
      obj2: {
        name: 'zhang',
        fun: test
      }
    }
    
    obj1.obj2.fun()
    
  • 當(dāng)把對(duì)象的屬性值函數(shù)賦值給一個(gè)新的變量,就會(huì)變成一般形式函數(shù)調(diào)用

    function test() {
      console.log(this) // Window
      console.log(this.name) // wang
    }
    var name = 'wang'
    const obj1 = {
      name: 'fang',
      obj2: {
        name: 'zhang',
        fun: test
      }
    }
    var t = obj1.obj2.fun
    t()
    
  • 當(dāng)屬性值函數(shù)內(nèi)部還有函數(shù)

    function test() {
      console.log(this) // Window
      console.log(this.name) // wang
    }
    var name = 'wang'
    const obj = {
      name: 'fang',
      foo: function() {
        console.log(this) // obj
        test() // test 是一般形式函數(shù)調(diào)用
      }
    }
    
    obj.foo() // foo 是方法調(diào)用
    

3. call镜悉、apply 和 bind 用來(lái)改變 this 指向

  • call: fun.call(thisArg[, arg1[, arg2[, ...]]])祟辟,第一個(gè)參數(shù)是要綁定給 this 的值,后面?zhèn)魅雲(yún)?shù)列表侣肄。

    const obj = {
      name: 'fang'
    }
    function a() {
      console.log(this)
    }
    a.call(obj) // obj
    a.call(null) // 如果第一個(gè)參數(shù)是 null旧困、undefined,指向 Window(下同)
    
  • apply: fun.apply(thisArg[, [arg1, arg2, ...]]),可接收兩個(gè)參數(shù)吼具,第一個(gè)是綁定給 this 的值僚纷,第二個(gè)是數(shù)組。

    const obj = {
      name: 'fang'
    }
    function a() {
      console.log(this)
    }
    a.apply(obj) // obj
    a.apply(undefined) // Window
    
  • bind:fun.bind(thisArg[, arg1[, arg2[, ...]]])拗盒,與 call 相似怖竭,但是返回的是一個(gè)函數(shù),需要手動(dòng)去執(zhí)行陡蝇。

    const obj1 = {
      name: 'fang'
    }
    const obj2 = {
      name: 'wang'
    }
    function a() {
      console.log(this)
    }
    const b = a.bind(obj1)
    const c = a.bind(obj2)
    // 需要手動(dòng)執(zhí)行
    b() // obj1
    a() // Window痊臭,函數(shù)a不會(huì)受影響
    c() // obj2
    b.call(null) // obj1(綁定關(guān)系一旦確認(rèn)給新變量,新變量繼續(xù)使用 call登夫、apply广匙、bind 不會(huì)再次改變指向)
    c.bind(obj2)() // obj2
    

4. 箭頭函數(shù)

箭頭函數(shù)沒(méi)有自己的 this,看其定義時(shí)外層是否有函數(shù)恼策,如果有鸦致,外層函數(shù)的 this 就是內(nèi)部箭頭函數(shù)的 this,如果沒(méi)有涣楷,則 this 指向 Window蹋凝。

  • 箭頭函數(shù)外層沒(méi)有函數(shù)

    const arrow = () => {
        console.log(this.name) // wang
    }
    var name = 'wang'
    const obj = {
      name: 'fang',
      foo: function() {
        console.log(this) // obj
        arrow() // 看定義時(shí)
      }
    }
    obj.foo()
    
      var name = 'wang'
      const obj1 = {
        name: 'fang',
        obj2: {
          name: 'zhang',
          fun: () => {
              console.log(this) // Window
          }
        }
      }
      obj1.obj2.fun()
    
  • 箭頭函數(shù)外層有函數(shù),注意外層函數(shù)的 this 指向按照之前規(guī)則判斷

    var name = 'wang'
    const obj = {
      name: 'fang',
      foo: function() {
        console.log(this) // obj
        const arrow = () => {
            console.log(this) // 指向外層函數(shù) this
        }
        arrow()
      }
    }
    
    obj.foo()
    
  • 箭頭函數(shù)能否被改變指向总棵?

    var name = 'wang'
    const obj1 = {name: 'zhang'}
    const obj2 = {
      name: 'fang',
      foo: function() {
        console.log(this) // obj2
        const arrow = () => {
            console.log(this.name) // fang
        }
        arrow.call(obj1) // 箭頭函數(shù)不會(huì)改變 this 指向
      }
    }
    
    obj2.foo()
    

5. class 類(es6 嚴(yán)格模式)

  • 創(chuàng)建類實(shí)例后鳍寂,再去調(diào)用類的方法,this 指向?qū)嵗龑?duì)象

      class A {
        constructor({
          age,
          name
        }) {
          this.name = name
          this.age = age
        }
    
        test() {
          console.log(this) // {name:'fang', age:1}
        }
      }
    
      const a = new A({
        age: 1,
        name: 'fang'
      })
      a.test()
    
  • 直接通過(guò) prototype 對(duì)象調(diào)用 test情龄,指向 prototype

      class A {
        constructor({
          age,
          name
        }) {
          this.name = name
          this.age = age
        }
    
        test() {
          console.log(this)
        }
      }
    
      const a = new A({
        age: 1,
        name: 'fang'
      })
      a.test() // {name:'fang', age:1}
      console.log(A.prototype) // {constructor:f, test:f}
      A.prototype.test() // prototype(想想看是不是可以理解為方法調(diào)用)
    
  • 子類創(chuàng)建一個(gè)實(shí)例后迄汛,指向子類實(shí)例對(duì)象,包括子類調(diào)用父類的方法

      class A {
        constructor() {
          this.name = 1
          this.age = 1
          this.sex = 0
        }
          test1(){
              console.log(this)
          }
      }
      class B extends A {
        constructor({name,age}) {
          super() // super 必須置于 this 前
          this.name = name // 如果不寫骤视,繼承父類的屬性 1
          this.age = age // 如果不寫鞍爱,繼承父類的屬性 1
        }
    
        test2() {
          console.log(this)
        }
      }
      const b = new B({
        name: 3,
        age: 3
      })
      b.test2() // {age:3,name:3,sex:0}
      // 父類的方法被子類調(diào)用
      b.test1() // {age:3,name:3,sex:0}
    
  • 子類通過(guò) prototype 調(diào)用的指向與父類是有區(qū)別的

      class A {
        constructor() {
          this.name = 1
          this.age = 1
          this.sex = 0
        }
        test1(){
            console.log(this)
        }
      }
      class B extends A {
        constructor({name,age}) {
          super() // super 必須置于 this 前
          this.name = name // 如果不寫,繼承父類的屬性 1
          this.age = age // 如果不寫专酗,繼承父類的屬性 1
        }
        test2() {
          console.log(this)
        }
      }
      console.log(B.prototype) // A {constructor: ?, test2: ?} 注意與父類prototype的區(qū)別
      B.prototype.test1() // A {constructor: ?, test2: ?}
      B.prototype.test2() // A {constructor: ?, test2: ?}
    

6. vue 中的 this

一般來(lái)說(shuō)睹逃,在 vue 生命周期函數(shù)或自定義方法中 this 指向的是 vue 實(shí)例,但是要注意下面的3種情況祷肯。

  • 回調(diào)函數(shù) then 鏈?zhǔn)綄懛ㄓ闷胀ê瘮?shù)沉填,this 指向 undefined,可使用 _this=this 獲取 vue 實(shí)例

    let _this = this // vue實(shí)例
    /* eslint-disable */
    request().then( function (res){
      console.log(this) // undefined
      console.log(_this) // vue實(shí)例
    })
    
  • setTimeout 執(zhí)行普通函數(shù)指向 Window 佑笋,可使用箭頭函數(shù)獲取 vue 實(shí)例

    setTimeout(() => {
      console.log(this) // vue 實(shí)例
    }, 2000)
    
  • 不應(yīng)該使用箭頭函數(shù)來(lái)定義 method 函數(shù)翼闹,箭頭函數(shù)綁定了父級(jí)作用域的上下文,this 指向 undefined蒋纬。

    methods: {
      todo: () => console.log(this) // undefined
    }
    

以上理解如果有不對(duì)之處請(qǐng)指出猎荠。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末坚弱,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子关摇,更是在濱河造成了極大的恐慌荒叶,老刑警劉巖,帶你破解...
    沈念sama閱讀 212,718評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件输虱,死亡現(xiàn)場(chǎng)離奇詭異些楣,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)悼瓮,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,683評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)艰猬,“玉大人横堡,你說(shuō)我怎么就攤上這事」谔遥” “怎么了命贴?”我有些...
    開封第一講書人閱讀 158,207評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)食听。 經(jīng)常有香客問(wèn)我胸蛛,道長(zhǎng),這世上最難降的妖魔是什么樱报? 我笑而不...
    開封第一講書人閱讀 56,755評(píng)論 1 284
  • 正文 為了忘掉前任葬项,我火速辦了婚禮,結(jié)果婚禮上迹蛤,老公的妹妹穿的比我還像新娘民珍。我一直安慰自己,他們只是感情好盗飒,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,862評(píng)論 6 386
  • 文/花漫 我一把揭開白布嚷量。 她就那樣靜靜地躺著,像睡著了一般逆趣。 火紅的嫁衣襯著肌膚如雪蝶溶。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 50,050評(píng)論 1 291
  • 那天宣渗,我揣著相機(jī)與錄音抖所,去河邊找鬼。 笑死痕囱,一個(gè)胖子當(dāng)著我的面吹牛部蛇,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播咐蝇,決...
    沈念sama閱讀 39,136評(píng)論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼涯鲁,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼巷查!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起抹腿,我...
    開封第一講書人閱讀 37,882評(píng)論 0 268
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤岛请,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后警绩,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體崇败,經(jīng)...
    沈念sama閱讀 44,330評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,651評(píng)論 2 327
  • 正文 我和宋清朗相戀三年肩祥,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了后室。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,789評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡混狠,死狀恐怖岸霹,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情将饺,我是刑警寧澤贡避,帶...
    沈念sama閱讀 34,477評(píng)論 4 333
  • 正文 年R本政府宣布,位于F島的核電站予弧,受9級(jí)特大地震影響刮吧,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜掖蛤,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,135評(píng)論 3 317
  • 文/蒙蒙 一杀捻、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧蚓庭,春花似錦水醋、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,864評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至拳魁,卻和暖如春惶桐,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背潘懊。 一陣腳步聲響...
    開封第一講書人閱讀 32,099評(píng)論 1 267
  • 我被黑心中介騙來(lái)泰國(guó)打工姚糊, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人授舟。 一個(gè)月前我還...
    沈念sama閱讀 46,598評(píng)論 2 362
  • 正文 我出身青樓救恨,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親释树。 傳聞我的和親對(duì)象是個(gè)殘疾皇子肠槽,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,697評(píng)論 2 351