假设你有一个函数:
const myFunc = function () {
console.log('Function has been invoked');
}
您可以使用括号作为
myFunc()
来调用函数。
现在假设你有一个物体。即使函数是对象,您也不能使用括号调用对象:
const myObj = {};
myObj(); // TypeError: myObj is not a function
那么有没有办法让对象像JS中的函数一样可调用?
首先我想到了函数对象具有的内部方法
[[Call]]
。我尝试自己设置此属性,但出现错误:
const myObject = {
[[Call]]: function() {
console.log("My object was invoked!");
}
};
// ReferenceError: Call is not defined
然后我读到,在 EcmaScript 中无法自行配置此属性,因此无法访问和更改对象的此内部属性。
接下来我想到了Proxy,它有
apply()
陷阱来捕获函数对象的[[Call]]
方法。我尝试设置代理,但仍然出现错误:
const callableObject = new Proxy({}, {
apply: function() {
console.log("Callable object was invoked!");
}
});
callableObject(); // TypeError: callableObject is not a function
我尝试过改变原型链,让对象的原型是Function.prototype,但还是不行:
const obj = {};
Object.setPrototypeOf(obj, Function.prototype)
const callableObject = new Proxy(obj, {
apply: function() {
console.log("Callable object was invoked!");
}
});
callableObject(); // TypeError: callableObject is not a function
好像Proxy可以做到这一点,但我还是想不出办法。
我看到的唯一可能性就是首先创建一个函数,然后将其视为对象,然后在需要时调用它。
函数本身就是一个对象:
console.log(Object.getPrototypeOf(Function.prototype).constructor.name);
const obj = function(){};
obj.prop = 'test';
console.log(obj.prop);
所以你可以直接将函数用作对象,但要小心函数的 props,如
name
、length
等。
由于您的语法非常灵活,超越了
const obj = {}
并允许使用代理,因此您可以代理函数,但将道具单独保存在专用对象中。所以代理函数将是对象的访问器:
const obj = {};
const callableObject = new Proxy(new Function, {
apply() {
console.log("Callable object was invoked!");
},
get(_, prop){
return Reflect.get(obj, prop);
},
set(_, prop, val){
Reflect.set(obj, prop, val);
}
});
callableObject();
callableObject.prop = 'test';
console.log(callableObject.prop, obj.prop);