【面试题】从源码来理解 fn1.call.call(fn2)
从源码来理解 fn1.call.call(fn2)
-
问题如下:
function fn1() {
console.log("1")
}
function fn2() {
console.log(2)
}
fn1.call(fn2)
fn1.call.call(fn2)
问:输出结果是多少?
答案:
1 2
解题思路:
对于第一个fn1.call(fn2),相信大家不难理解,这里调用了fn1函数,虽然改变了 this 指向,但是并不影响结果
我们这里着重看第二个 fn1.call.call(fn2) 的解题思路:
为了方便理解,我们将会从 call源码 的角度来理解,这里我们来写一个 mycall 方法来模拟 call
Function.prototype.mycall = function (context, ...args) {
// 如果为传入 context 或传入 null 将其指向指为 window
context = context || window
// 记录 mycall 的 this 指向
context.fn = this
// 调用 context.fn(...args) 并记录函数结果
const result = context.fn(...args)
// 删除 fn
delete context.fn
// 返回结果
return result
}
fn1.mycall.mycall(fn2)
可以通过代码逐行分析来理解 fn1.call.call(fn2),当然,也可以通过浏览器调试来对照理解
/* 这里代码的运行经历了两轮 可以逐轮理解 */
Function.prototype.mycall = function (context, ...args) {
// 第一轮
// 调用 fn1.mycall.mycall(fn2) 进入mycall
// context -> fn2
// 第二轮
// 未传入参数
// context -> window
context = context || window
// 第一轮
// 此处的 this 指向mycall(fn2)之前的内容 即 mycall
// context.fn -> this -> mycall
// fn2.mycall
// 第二轮
// context.fn -> this -> fn2
// window.fn2
context.fn = this
// 第一轮
// 执行 fn2.mycall(没有参数) 进入第二轮
// 第二轮
// 执行 window.fn2(没有参数) 输出 2
const result = context.fn(...args)
delete context.fn
return result
}
扩展
fn1.call.call.call(fn2)
做法相同,在此基础上增加 call 的调用并不影响结果,答案也为 2,有兴趣也可以调试代码来看看
上一篇:
Java基础知识总结(2021版)
下一篇:
【前端面试题】Vue2和Vue3的区别
