你能搞懂JS的this指向問題嗎?看看這篇文章

2022-03-25 13:00:19
你能搞懂JavaScript的this指向問題嗎?下面本篇文章帶大家聊聊這令人煩惱的this指向問題,希望對大家有所幫助!

this的指向

在我們看見的各種介紹如何判斷this的指向方法中,"this的最終指向的是那個呼叫它的物件" 這句話被視作核心,但是面對多種多樣的情況,我們容易搞混。針對針對多種情況結合我的理解,我提出了一句話 「箭頭,定時和構造,特殊情況特殊看,普通呼叫看點號,後面有點不看前,然後就近原則判,最後剩下就是window」。【相關推薦:】

箭頭函數

箭頭函數的本身沒有this,所有不存在this改變,它捕獲外層的this使用

var name = "windowsName";
var a = {
    name: "Cherry",
    fn() {
      setTimeout(()=>{
        console.log(this.name); 
      },0)
    }
}

a.fn() //Cherry

解析: 首先物件a呼叫fn函數,所以fn函數的this指向物件a,然後箭頭捕獲外層this,那麼就不是setTimeout裡的this,而是fn函數的this,所以最後拿到物件a裡的name

定時器

對於延時函數內部的回撥函數的this指向全域性物件window

var name = "windowsName";
var a = {
    name: "Cherry",
    fn() {
      setTimeout(function (){
        console.log(this.name); 
      },0)
    }
}

a.fn() //windowsName

解析: 首先物件a呼叫fn函數,然後這裡setTimeout裡的回撥函數是匿名函數,為普通的函數,那麼匿名函數中的this指向的就是window

var name = "windowsName";
var b={
  name: "setTimeoutName"
}
var a = {
    name: "Cherry",
    fn() {
      setTimeout((function (){
        console.log(this.name); 
      }).bind(b),0)
    }
}

a.fn() //setTimeoutName

解析:首先物件a呼叫fn函數,然後這裡setTimeout裡的回撥函數是匿名函數,為普通的函數,那麼匿名函數中的this指向的就是window,但使用bind改變匿名函數的this指向為物件b,所以最後物件b裡的name

建構函式

建構函式中的this指向建立的範例物件,

注意:如果建構函式中返回一個物件,建立時不會有新的範例物件,而是這個返回的物件

function fn(){
  this.age = 37;
}

var a = new fn();
console.log(a.age); // 37
a.age = 38;
console.log(fn); // { this.age = 37; }
console.log(a.age); // 38

解析:這裡我們通過建構函式建立範例物件a,相當於開闢一個新地方將建構函式內容複製過來,就有了a物件,這時候this指向的就是物件a,我們修改物件a中內容不影響建構函式

點號判斷

通過.判斷this指向,遵循就近原則

var a = {
  age:10,
  b: {
      age:12,
      fn(){
          console.log(this.age); 
      }
  }
}
a.b.fn(); //12

解析:物件a呼叫物件b的fn函數,fn函數前面有兩個.,那麼最近的是物件b,所以fn函數的this指向的就是物件b,最後拿到的就是物件b的age

var a = {
  age:10,
  b: {
      age:12,
      fn(){
          console.log(this.age); //undefined
      }
  }
}
var c = {
  age:20,
}

var d = {
  age:30,
}
a.b.fn.bind(c).bind(d)(); //20

解析:物件a呼叫物件b的fn函數然後使用bind改變this的指向,這時候fn前後前後都有.,不看前面的.,只用看後面的,然後最近的bind改變this指向為c,那麼此時fn函數的this指向的就是物件c,拿到的就是物件c的age

練習

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

outerFunc.bind({ x: 1 })()
obj = {
  func() {
    const arrowFunc = () => {
      console.log(this._name)
    }

    return arrowFunc
  },

  _name: "obj",
}

obj.func()() //obj

func = obj.func
func()()  //undefined

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

obj.func.bind()()() //undefined

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

apply、call、bind

使用 apply、call、bind 函數可以改變this的指向,上面this的例子中使用到

區別

thisArg , [ argsArray] call(thisArg, arg1, arg2, ...)

apply和call函數區別在於this後面傳入的引數,apply中傳的是一個陣列,而call中傳入的是展開的引數

bind(thisArg[, arg1[, arg2[, ...]]])()

  • 然後bind函數建立的是一個新的函數,需要手動去呼叫
  • 這個新函數的 this 被指定為 bind() 的第一個引數,而其餘引數將作為新函數的引數,供呼叫時使用

如有錯誤,請大家指正!!感謝大家閱讀!

參考資料

https://juejin.cn/post/6946021671656488991#comment

【相關視訊教學推薦:】

以上就是你能搞懂JS的this指向問題嗎?看看這篇文章的詳細內容,更多請關注TW511.COM其它相關文章!