首頁 >web前端 >js教程 >一文講解js中this指向問題(附程式碼)

一文講解js中this指向問題(附程式碼)

奋力向前
奋力向前轉載
2021-09-17 10:16:281713瀏覽

之前的文章《中秋技巧篇:如何用CSS實現地球和月亮的公轉(收藏)》中,給大家介紹瞭如何用CSS實現地球和月亮的公轉。以下這篇文章給大家了解js中this指向問題,有一定的參考價值,有需要的朋友可以參考一下,希望對你們有所助。

一文講解js中this指向問題(附程式碼)

JS中this指向問題

相信我,只要記住本文的7步口訣,就能徹底掌握JS 中的this指向。

先念口訣:箭頭函數、new、bind、apply 和 call、歐比屆點(obj.)、直接呼叫、不在函數裡。

依照口訣的順序,只要滿足前面某個場景,就可以確定this指向了。

接下來依照口訣順序對它們進行詳解,文中範例程式碼都運行在ChromeConsole控制台中。

文末有精心準備的練習題,用於檢驗學習成果,別忘了試試~

1. 箭頭函數

#箭頭函數排在第一個是因為它的this不會被改變,所以只要目前函數是箭頭函數,那就不用再看其他規則了。

箭頭函數的this是在建立它時外層this的指向。這裡的重點有兩個:

1、創建箭頭函數時,就已經確定了它的this#指向。

2、箭頭函數內的this指向外層的this

所以要知道箭頭函數的this就得先知道外層this#的指向,需要繼續在外層應用七步驟口訣。

2. new

當使用 new 關鍵字呼叫函數時,函數中的 this 一定是 JS 建立的新物件。

讀者可能會有疑問,「如果使用new關鍵呼叫箭頭函數,是不是箭頭函數的this#就會被修改呢?」。

我們在控制台試一下。

func = () => {} 
new func() // throw error

一文講解js中this指向問題(附程式碼)

從控制台中可以看出,箭頭函數不能當做建構函數,所以不能與new一起執行。

3. bind

bind 是指 Function.prototype.bind() 詳細位址:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript /Reference/Global_Objects/Function/bind

多次bind 時只認第一次bind 的值

易錯點

function func() {
  console.log(this)
}

func.bind(1).bind(2)() // 1

箭頭函數中this 不會被修改

func = () => {
  // 这里 this 指向取决于外层 this,参考口诀 7 「不在函数里」
  console.log(this)
}

func.bind(1)() // Window,口诀 1 优先

bind 與new

易錯點

function func() {
  console.log(this, this.__proto__ === func.prototype)
}

boundFunc = func.bind(1)
new boundFunc() // Object true,口诀 2 优先

4. apply 和call

apply()call()的第一個參數都是this,差別在於透過apply呼叫時實參是放到陣列中的,而透過 call呼叫時實參是逗號分隔的。

箭頭函數中this 不會被修改

易錯點

func = () => {
  // 这里 this 指向取决于外层 this,参考口诀 7 「不在函数里」
  console.log(this)
}

func.apply(1) // Window,口诀 1 优先

bind 函數中this 不會被修改

易錯點

function func() {
  console.log(this)
}

boundFunc = func.bind(1)
boundFunc.apply(2) // 1,口诀 3 优先

5. 歐比屆點(obj.)

function func() {
  console.log(this.x)
}

obj = { x: 1 }
obj.func = func
obj.func() // 1

這裡就不用程式碼例證箭頭函數和bind 函數的優先權更高了,有興趣可自行嘗試吧。

6. 直接呼叫

在函數不滿足前面的場景,直接呼叫時,this將指向全域物件。在瀏覽器環境中全域物件是Window,在Node.js環境中是Global

先來個簡單的例子。

function func() {
  console.log(this)
}

func() // Window

來一個複雜的例子,外層的outerFunc就起個迷惑目的。

function outerFunc() {
  console.log(this) // { x: 1 }

  function func() {
    console.log(this) // Window
  }

  func()
}

outerFunc.bind({ x: 1 })()

7. 不在函數裡

不在函數中的場景,可分為瀏覽器的<script></script>標籤裡,或Node.js的模組檔案裡。

1、在<script></script>標籤裡,this指向Window

2、在Node.js的模組檔案裡,this指向Module的預設導出對象,也就是module. exports

非嚴格模式

嚴格模式是在ES5提出的。在ES5規範之前,也就是非嚴格模式下,this不能是undefinednull。所以**在非嚴格模式下,透過上面七步驟口訣,如果得出this#指向是undefinednull,那麼this會指向全域物件。 **在瀏覽器環境中全域物件是Window,在Node.js環境中是Global

例如下面的程式碼,在非嚴格模式下,this都指向全域物件。

function a() {
  console.log("function a:", this)
  ;(() => {
    console.log("arrow function: ", this)
  })()
}

a()

a.bind(null)()

a.bind(undefined)()

a.bind().bind(2)()

a.apply()

非嚴格模式下執行結果為:

一文講解js中this指向問題(附程式碼)

在严格模式下,执行同样的代码进行对比。记住要一次性将所有代码复制粘贴到控制台中,才能运行在严格模式下(因为第一行 "use strict" 才会对后面的代码生效)。

"use strict"

function a() {
  console.log("function a:", this)
  ;(() => {
    console.log("arrow function: ", this)
  })()
}

a()

a.bind(null)()

a.bind(undefined)()

a.bind().bind(2)()

a.apply()

严格模式下执行结果为:

一文講解js中this指向問題(附程式碼)

七步口诀在严格模式下和非严格模式下都是完备的,只是在非严格模式下nullundefined会被转换为全局对象。所以我没有将这点列入口诀中。

做题复习

先背诵口诀再做题,“箭头函数、newbindapplycall、欧比届点(obj.)、直接调用、不在函数里”。

1. 下面代码执行后,func.count 值为多少?

function func(num) {
  this.count++
}

func.count = 0
func(1)

答案

func.count值为 0。

按照口诀,func()调用时属于第 6 类「直接调用」。在非严格模式下,this指向全局对象。thisfunc 一点关系都没有,所以 func.count保持不变so easy

2. 以下箭头函数中 this 指向谁呢?

obj = {
  func() {
    const arrowFunc = () => {
      console.log(this._name)
    }

    return arrowFunc
  },

  _name: "obj",
}

obj.func()()

func = obj.func
func()()

obj.func.bind({ _name: "newObj" })()()

obj.func.bind()()()

obj.func.bind({ _name: "bindObj" }).apply({ _name: "applyObj" })()

答案

// obj
// undefined
// newObj
// undefined
// bindObj

是不是很简单,你学废了吗?

推荐学习:JS视频教程

以上是一文講解js中this指向問題(附程式碼)的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文轉載於:juejin.im。如有侵權,請聯絡admin@php.cn刪除