前言
我们知道call方法可以改变this的指向
使用方法如下
const book = '《十万个为什么》'
function log() {
console.log('这本书是' + this.book)// this默认指向全局window对象
}
log() // 这本书是《十万个为什么》
const instance = {book:'《从你的全世界路过》'}
// 改变this指向instance
log.call(instance)// 这本书是《从你的全世界路过》
log函数中使用了this
关键字,this默认指向window
的原因是,声明一个函数时都默认挂在window身上
而后通过call
方法使this执行了新的对象instance
this指向问题
到这里就不得不聊一聊,this到底指向谁,怎么判断?怎么修改this指向?
简单来说就是,一个方法被"谁"
调用,this就指向"谁"
这里的"谁"可以是一个对象、一个数组、甚至是一个函数。
因为在js里边,万物皆对象。
举个栗子:
const jay = {
name: 'jay',
sayhello() {
console.log('Nice to see you, I am ' + this.name);
}
}
jay.sayhello()// Nice to see you, I am jay
const cindy = {
name: 'cindy',
sayhello() {
console.log('Nice to see you, I am ' + this.name);
}
}
jay.sayhello()// Nice to see you, I am cindy
const list = [1, 2, 3]
list.sayhello = () => {
console.log('Nice to see you, I have ' + this.length + 'items');
}
list.sayhello()// Nice to see you, I have 3 items
可以看到,谁调用了sayhello,this就指向谁
call实现原理
那么call是如何改变this指向的呢?
手写一个$call,避免覆盖原生call方法
/**
* call实现原理
*/
Function.prototype.$call = function (context,...args) {
const fn = this // 调用call方法的目标函数
context.fn = fn // 函数挂到目标对象身上
context.fn(...args)// 执行fn并传参,这时候this已经执行context了,因为fn是contex调用的
delete context.fn// 记得删除fn,不要污染原对象
}
// 使用方法
function say(name) {
console.log(name + this.age + '岁了');
}
const obj = { age: 23 }
say.$call(obj, 'sea')// sea23岁了
- 任意函数只要调用了$call方法,就会被挂载到新的对象context上去,
- 然后调用context里边的临时fn,这样就会把this指向context
- 最后删除临时fn是为了保证不改变原来的对象
apply实现原理
与call的实现原理相同,就是传参的方式略微不同。传的是一个数组。
Function.prototype.$apply = function (context,args = []) {
const fn = this
context.fn = fn
context.fn(...args)
delete context.fn
}