1. 程式人生 > >js改變this指向的方法:call apply bind

js改變this指向的方法:call apply bind

  • 在函式中使用this
function foo(c, d) {
  return this.a + this.b + c + d
}

global.a = 3
global.b = 4

// foo執行時,this沒有明確的指向,預設指向全域性物件global
// nodejs中是global,browser中是window
foo(3, 4)               // 14

call apply bind是函式Function原型的方法,所有函式繼承自Function.prototype

foo.call === Function.prototype.call    // true
foo.apply === Function.prototype.apply // true foo.bind === Function.prototype.bind // true
  • call() apply()

this會暫時繫結call和apply的第一個引數。傳遞null和undefined,this將繫結到全域性物件global。後面的引數,call接收的是引數列表,apply接收的是引數陣列。

let o = {a: 1, b: 2}

// foo.call(obj, ...[arguments])
foo.call(o, 3, 4)       // 10
foo.call(null
, 3, 4) // 14 foo.call(undefined, 3, 4) // 14 foo.call(global, 3, 4) // 14 // foo.apply(obj, [arguments]) foo.apply(o, [3, 4]) // 10 foo.apply(null, [3, 4]) // 14

call apply bind的第一個引數如果不是物件,會先呼叫內部的ToObject方法轉換成物件。

function foo(){
  return typeof this
}

// 分別呼叫Number和String的constructor
foo.call(1)     // object, new Number(1)
foo.call('a') // object, new String('a')

es6支援使用擴充套件運算子,一些情況下可以不再使用call、apply、bind。

// 求陣列最大值
let arr = [4, 3, 2, 1]
Math.max.call(null, ...arr) // 4
Math.max.apply(null, arr)   // 4
Math.max(...arr)            // 4

// 資料型別判斷
Object.prototype.toString.call(1)   // [object Number]
Object.prototype.toString.call('a') // [object String]

new (Date.bind.apply(Date, [null, 2018, 5, 26]))
new Date(...[2018, 5, 26])
  • bind()

函式的bind方法會建立一個新的函式,新函式中的this會永久繫結bind傳入的第一個引數,其他引數初始化後也不會改變。

let o = {a: 1, b: 2}

let f1 = foo.bind(o, 3, 4)
let f2 = f1.bind(null, 10, 10)

f1()    // 10
f2()    // 10, 並沒有繫結global, 引數c和d的值也沒有改變
f1 === f2   // false, f1和f2並不相等
f1.call(null, 10, 10)   // 10, 在f1上使用call仍然沒有改變