前言
先说明每个方法如何使用
- 三个方法都是为了改变方法执行的 this 指向
- call、apply是调用后改变 this 立即执行
- bind 是返回一个改变 this 执行的函数,在实际调用时确定 this 并执行
call 使用
function add (a, b) {
console.log(this + a + b)
}
add.call(1, 2, 3)
- 需要实现执行 add 函数时改变其 this 指向,如果直接执行 add(2, 3)则 this 指向为 window,确定 this 指向就看谁调用了函数,那么需要实现 1.add(2, 3),this则为1
- 而 1 是 number 基本类型不会有方法,所以当传入的this不是对象类型就先将 this 包装为对象,然后为 this 添加函数(要改变 this 指向的函数),接着执行 this.f(params) 调用时就改变了原函数的 this 指向
call 实现
将要执行的函数添加到this属性上,然后调用 this.f(...params),即实现了f的this执行为传入的 this的调用
Function.prototype.call = function(thisValue, ...params) {
if (typeof thisValue !== 'object') {
thisValue = new Object(thisValue)
}
let context = this
thisValue.f = context
// 定义为不可枚举
Object.defineProperty(thisValue, 'f', {
enumerable: false,
get () {
return context
}
})
thisValue.f(...params)
// 删除为 this 临时添加的函数
delete thisValue.f
}
apply 使用
function add (a, b) {
console.log(this + a + b)
}
add.apply(1, [2, 3])
apply 实现
Function.prototype.apply = function (thisValue, params) {
if (thisValue !== 'object') {
thisValue = new Object(thisValue)
}
let context = this
thisValue.f = context
Object.defineProperty(thisValue, 'f', {
enumerable: false,
get () {
return context
}
})
thisValue.f(...params)
delete thisValue.f
}
bind 使用
function add (a, b, c) {
console.log(this)
console.log(a, b)
console.log(c)
}
let add2 = add.bind({ value: 1 }) // 返回一个改变 this 指向的函数
add2(2, 3) // 真实执行
返回一个改变 this 执行的函数
bind 实现
将要执行的函数添加到this的属性上, 然后返回一个可接受参数的函数,该函数内部执行 this.f(arg1.concat(arg2)),执行函数,参数为绑定时的参数concat执行时的参数
Function.prototype.bind = function(thisValue, ...args) {
if (typeof thisValue !== 'object') {
thisValue = new Object(thisValue)
}
let context = this
thisValue.f = context
Object.defineProperty(thisValue, 'f', {
enumerable: false,
get () {
return context
}
})
return function (...args2) {
thisValue.f(...args.concat(args2))
}
}
✿✿ヽ(°▽°)ノ✿ 完成啦