问题描述
我想知道是否有一种方法可以修改TypeScript中的函数并访问其中的原始函数。这是我如何使其工作的示例:
let obj = {
shout: () => {
console.log("AHHHHH!");
},};
let s = obj.shout;
obj.shout = () => {
console.log("I'm going to shout.");
s();
};
obj.shout(); //-> "I'm going to shout","AHHHHH!"
通过这种方式,无论何时调用它,我都可以向我的喊叫功能添加警告-但我觉得这样做很丑陋,所以我想知道是否有更好的方法。
解决方法
OP的方法是最直观/自然的方法。对于JavaScript应用程序,有时需要 拦截 和/或 修改 控件功能 ,一个人不拥有或由于其他原因而被禁止触摸。
对于这种情况,除了包装原始实现来保留和更改这种逻辑外,别无其他方法。此功能并非JavaScript独有。已有很长的编程语言可以通过 Reflection 和 Self->实现 元编程 修改 。
当然,人们可以/应该为所有可能想到的修饰符用例提供防弹但方便的抽象……从最明显,最容易实现的OP用例开始,这可以由例如 before 修饰符...
处理
const obj = {
shout: function (...args) {
console.log('AHHHHH!');
console.log('args : ',args);
console.log('this is me : ',this);
}
};
obj.shout();
obj.shout = obj.shout.before(function () {
console.log("I'm going to shout.");
},obj);
obj.shout('test of "before" modifier');
const anotherOne = {
name: 'anotherOne'
};
obj.shout.call(anotherOne,'delegation and self reflection');
/*
console.log(
'Object.getOwnPropertyDescriptors(Function.prototype) :',Object.getOwnPropertyDescriptors(Function.prototype)
);
*/
.as-console-wrapper { min-height: 100%!important; top: 0; }
<script>
(function (Function) {
const fctPrototype = Function.prototype;
const FUNCTION_TYPE = (typeof Function);
function isFunction(type) {
return (
(typeof type == FUNCTION_TYPE)
&& (typeof type.call == FUNCTION_TYPE)
&& (typeof type.apply == FUNCTION_TYPE)
);
}
function getSanitizedTarget(target) {
return ((target != null) && target) || null;
}
function before/*Modifier*/(handler,target) {
target = getSanitizedTarget(target);
const proceed = this;
return (
isFunction(handler) &&
isFunction(proceed) &&
function () {
const context = target || getSanitizedTarget(this);
const args = arguments;
//handler.apply(context,args);
handler.call(context,args);
return proceed.apply(context,args);
}
) || proceed;
}
// before.toString = () => 'before() { [native code] }';
Object.defineProperty(fctPrototype,'before',{
configurable: true,writable: true,value: before/*Modifier*/
});
}(Function));
</script>
从使用附加提供的实现的示例代码中可以看出,Function.prototype
非常适合在JavaScript中启用 方法修饰符 。
但是,无论如何/在何处实现此类修改器功能,以下内容都适用于任何可靠的修改器代码(
- 修饰符必须支持
target
对象(用于根据需要委派正确的this
上下文)。 - 修饰符必须正确地转发包装方法的参数,或者分别处理其调用失败的异常的返回值。
我不介意有一天JavaScript正式启用... Function.prototype[
before
|
after
|
around
|
afterThrowing
|
afterFinally
]
。
当您为现有对象分配新功能时,就像丢失了对旧值的引用一样。
但是,如果您使用类,则可以通过super
来访问重载方法。
class ObjA {
shout() {
console.log('AHHHHH!')
}
}
class ObjB extends ObjA {
shout() {
super.shout()
console.log("I'm going to shout.")
}
}
const obj = new ObjB()
obj.shout() //-> "I'm going to shout","AHHHHH!"