通过实现模拟call和apply,深入理解call和apply是如何改变this。
call
简单概述call:
call()方法在使用一个指定的this值和若干个指定的参数值的前提下调用某个函数或方法。
举个栗子:
let baby = {
name: "George"
}
function getName(age) {
return {
name: this.name,
age
}
}
getName.call(baby, 1) // {name: "George", age: 1}
注意:
- call改变了this的指向,主到了baby
- getName函数执行了
模拟实现
我们假设最后这样调用函数:
getName.simulateCall(baby, 1)
因为getName是函数,我们在Function.prototype上进行扩展。设想,函数的调用是在某个对象上触发的,即调用位置上存在上下文对象,例如XXX.getName()
var name = 'ALin'
let baby = {
name: "George"
}
function getName(age) {
return {
name: this.name,
age
}
}
Function.prototype.simulateCall = function(context, ...args) {
let ctx = context || window
ctx.fun = this
const result = ctx.fun(...args)
delete ctx.fun
return result
}
getName.call(baby, 1) // {name: "George", age: 1}
getName.call(null, 16) //{name: 'Alin', age: 16}
getName.simulateCall(baby, 1) // {name: "George", age: 1}
getName.simulateCall(null, 18) // {name: "Alin", age: 18}
apply的模拟实现
apply 的实现跟 call 类似,后面的参数格式为数组而已,直接上代码
var name = 'ALin'
let baby = {
name: "George"
}
function getName(age) {
return {
name: this.name,
age
}
}
Function.prototype.simulateApply = function(context, args) {
let ctx = context || window
ctx.fun = this
const result = ctx.fun(...args)
delete ctx.fun
return result
}
getName.apply(baby, [1]) // {name: "George", age: 1}
getName.apply(null, [1]) // {name: "Alin", age: 1}
getName.simulateApply(baby, [1]) // {name: "George", age: 1}
getName.simulateApply(null, [1]) // {name: "Alin", age: 1}
好了,辣么问题来了,如何模拟bind呢?