这三个方法在平时开发中经常会用到,鉴于还有一部分人不太了解,本篇文章集中说下它们的具体用法。
首先,三个方法都是在Function.prototype定义的,即:
Function.prototype.callFunction.prototype.applyFunction.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
apply和call的作用相同,只是参数格式不一样
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方法的功能和call、apply相同,只是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