新手入门:Javascript的call、apply和bind

479 阅读2分钟
原文链接: www.codemore.top

这三个方法在平时开发中经常会用到,鉴于还有一部分人不太了解,本篇文章集中说下它们的具体用法。

首先,三个方法都是在Function.prototype定义的,即:

  • Function.prototype.call
  • Function.prototype.apply
  • Function.prototype.bind

因为Javascirpt中函数是Function的实例,即函数的原型对象里定义的这三个方法,所以函数可以调用这三个方法,对象不可以:

function foo() {
  console.log('i am foo')
}

console.log(getPrototypeOf(foo) === Function.prototype)
// true

console.log(typeof foo.call) // 'function'
console.log(typeof foo.apply) // 'function'
console.log(typeof foo.bind) // 'function'

const obj = {name: 'foo'}
// 或者
const obj_2 = Object.create(null)

console.log(typeof obj.call) // 'undefined'
console.log(typeof obj_2.call) // 'undefined'

Function.prototype.call

语法

function.call(thisArg, arg1, arg2, ...)

参数

  • thisArg: 可选,指向一个对象的引用
  • arg1, arg2, ...: 可选,函数参数

用法

通过call来调用函数function.call(thisArg), 使得函数内的this指向对象thisArg,这样可以省去在对象里重复定义方法:

// 公用方法
function Production(name, price) {
  this.name = name;
  this.price = price;
}

function Food(name, price) {
  Production.call(this, name, price)
  this.category = 'food';
}

function Toy(name, price) {
  Production.call(this, name, price)
  this.category = 'toy';
}

var cheese = new Food('feta', 5); // {name: feta, price: 5}
var fun = new Toy('robot', 40) // {name: robot, price: 40}

// Production是个公用方法
// 每次new 一个实例`Foo`或者`Toy`时
// Production方法内的`this`分别指向不同的实例对象
// 所以通过call来调用Production方法
// 可以分别为不同的对象设置属性: `name`和`price`

Function.prototype.apply

applycall的作用相同,只是参数格式不一样

call接收参数列表,apply接收数组形式的参数

var arr = [1, 2, 3]

arr.push.apply(arr, [4, 5, 6])

console.log(arr) // [1, 2, 3, 4, 5, 6]

Function.prototype.bind

bind方法的功能和callapply相同,只是bind方法不是直接调用函数并执行,而是返回一个改变了原函数内部this指向的新函数

var obj = {msg: 'i am foo'}

function foo() {
  console.log(this.msg)
}

foo.call(obj) // i am foo

const bar = foo.bind(obj)
// 返回一个内部`this`指向`obj`的新函数
bar() // i am foo

同时,bind方法可以接收任意参数

var obj = {msg: 'i am foo'}

function foo(welcome) {
  console.log(`${welcome}, ${this.msg}`)
}

var bar = foo.bind(obj, 'hello')

bar() // hello, i am foo

如果原函数有参数,请注意参数顺序:

var obj = {msg: 'i am foo'}

function foo(welcome) {
  const mobile = [].slice.call(arguments, 1).join('')
  console.log(`${welcome}, ${this.msg}, 我的电话: ${mobile}`)
}

var bar = foo.bind(obj, 'hello')

bar(1, 2, 3, 4, 5, 6) // hello, morning, i am foo, 我的电话: 123456