關於-this指向的理解

muddyrain發表於2021-01-19

this 的不同應用場景,如何取值

  • 作為普通函式被呼叫

  • 使用 call apply bind

  • 作為物件方法被呼叫

  • 在class方法中呼叫

  • 箭頭函式 (找上級作用域)

this 取什麼值是在函式執行的時候確認的,不是在函式定義的時候確認的
/* 
    this 指向  window  因為   他當做執行函式 執行函式會直接確認this指向
*/
/*
     this 指向 當前物件  因為   箭頭函式 作為回撥函式來使用  只有當函式被呼叫的    時候才會觸發  this指向
*/ 
const pepole = {
    await(){
        setTimeout(function (){
            console.log(this);   
        }) 
        setTimeout(() =>{
            console.log(this);  
        })
    }
}

call, apply, bind都是改變函式執行的上下文,說的直白點就是改變了函式this的指向。不同的是:call和apply改變了函式的this,並且執行了該函式,而bind是改變了函式的this,並返回一個函式,但不執行該函式。

call 內部實現原理

call() 方法呼叫一個函式, 其具有一個指定的 this 值和分別地提供的引數(引數的列表)。

注意:該方法的作用和 apply() 方法類似,只有一個區別,就是 call() 方法接受的是若干個引數的列表,而 apply() 方法接受的是一個包含多個引數的陣列。

語法:

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

引數:

  • thisArg

    • 在 fun 函式執行時指定的 this 值
    • 如果指定了 null 或者 undefined 則內部 this 指向 window
  • arg1, arg2, ...

    • 指定的引數列表
    Function.prototype.call = function(thisArg, args) {
      // this指向呼叫call的物件
      if (typeof this !== 'function') { // 呼叫call的若不是函式則報錯
          throw new TypeError('Error')
      }
      thisArg = thisArg || window
      thisArg.fn = this   // 將呼叫call函式的物件新增到thisArg的屬性中
      const result = thisArg.fn(...[...arguments].slice(1)) // 執行該屬性
      delete thisArg.fn   // 刪除該屬性
      return result
    }

apply 內部實現原理

apply() 方法呼叫一個函式, 其具有一個指定的 this 值,以及作為一個陣列(或類似陣列的物件)提供的引數。

注意:該方法的作用和 call() 方法類似,只有一個區別,就是 call() 方法接受的是若干個引數的列表,而 apply() 方法接受的是一個包含多個引數的陣列。

語法:

fun.apply(thisArg, [argsArray])

引數:

  • thisArg
  • argsArray

apply()call() 非常相似,不同之處在於提供引數的方式。
apply() 使用引數陣列而不是一組引數列表。例如:

fun.apply(this, ['eat', 'bananas'])
Function.prototype.apply = function(thisArg, args) {
    if (typeof this !== 'function') { 
        throw new TypeError('Error')
    }
    thisArg = thisArg || window
    thisArg.fn = this
    let result
    if(args) {
        result = thisArg.fn(...args)
    } else {
        result = thisArg.fn()
    }
    delete thisArg.fn
    return result
}

bind 內部實現原理

bind後的函式會返回一個函式,而這個函式也可能被用來例項化

bind方法後面有一對空格,所以得出結論bind返回的是一個函式必須呼叫才會執行 bind({x:20})()

語法:

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

返回值:返回由指定的this值和初始化引數改造的原函式的複製。

Function.prototype.bind = function(thisArg) {
    if(typeof this !== 'function'){
        throw new TypeError(this + 'must be a function');
    }
    // 儲存函式本身
    const _this  = this;
    // 去除thisArg的其他引數 轉成陣列
    const args = [...arguments].slice(1)
    // 返回一個函式
    const bound = function() {
        // 可能返回了一個建構函式,我們可以 new F(),所以需要判斷
        if (this instanceof bound) {
            return new _this(...args, ...arguments)
        }
        // apply修改this指向,把兩個函式的引數合併傳給thisArg函式,並執行thisArg函式,返回執行結果
        return _this.apply(thisArg, args.concat(...arguments))
    }
   return bound
}

對 bind this 指向的 一些總結

bind this 指向問題 ,就是 誰呼叫,在哪裡呼叫,this指向 就會在哪裡 傳送, 並且this 就會指向 他。

簡單來說 就是 this 指向 是 根據自由變數來決定的 ,自由變數在他被呼叫 ,被使用的 時候 他會在 他的作用域來進行查詢 這個當前 使用的 變數 ,然後根據 他 需要訪問的變數 ,然後 來 使他這個 變數值進行 改變,this 指向的是在 哪裡 進行呼叫 ,就會在哪個作用域中進行呼叫。

自由變數的查詢,是在函式定義的地方,向上級作用域查詢,不是在執行的地方查詢!

this指向的是當前物件。如果在全域性範圍內使用 this ,則指代當前頁面 window 如果在函式中使用this, 則this指代什麼是根據當前函式是什麼物件上呼叫。我們可以callapplybind 改變函式中 this 的 具體指向
本作品採用《CC 協議》,轉載必須註明作者和本文連結

相關文章