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

时间:2022-10-15 18:34:33
  • 在函数中使用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仍然没有改变