不对原函数函数体进行修改的情况下为原函数增加新的功能也被称为函数调用拦截,在不直接修改原始代码的情况下,可以在被调用函数之前和/或之后进行某些操作,甚至可以替换被拦截的调用函数
//原函数
let Fn = function () {
console.log('原始功能');
}
//准备一个中间变量
let temp = Fn;
//将新的功能函数赋值给Fn
Fn = function() {
//新功能函数体内调用temp
temp();
//拓展功能
console.log('拓展功能');
}
//调用Fn
Fn() // 先输出原始功能,再输出拓展功能
其实涉及到的知识点很简单,主要是作用域与js数据类型
由于js函数是引用/复杂数据类型,存储在堆中,对函数的引用(指针)存储在栈中. 将一个函数赋值给变量Fn,实质上是将该函数的在堆中的地址赋值给Fn,随后将Fn赋值给变量temp也是如此.
关键在于全局变量temp,在新的函数体中不使用关键字直接声明变量temp并且使用它. 涉及temp的操作时,将沿着作用域链层层向上查找,直到已在全局声明的变量temp,而temp早已被赋值了原Fn的函数地址,因此会调用原Fn,在控制台输出原始功能,继续执行新函数体内的其他代码,输出拓展功能,利用这个特性,我们可以在被调用函数之前和/或之后进行我们需要执行的操作,甚至可以替换被拦截的调用函数.