以@amirnissim 的回答为基础。
正如我们大多数人可能已经知道的那样,ES6 引入了代理 API,它允许我们创建一个对象(代理对象)来捕获对该对象的调用,从而我们有机会“路由”用户调用的属性我们可能希望的任何对象。
模仿 PHP 的魔法方法
不幸的是,没有办法使用 Proxy 对象扩展一个类,但我们可以做的是设置一个中间步骤,将一个对象变成一个代理,并将任何传入的方法调用路由到对象本身可用的方法:
class MyProxy
{
constructor ()
{
return this.asProxy()
}
/**
* Return as a proxy with this object as its target.
*/
asProxy ()
{
let handler = {
/**
* This function is called whenever any property on the Proxy
* is called.
*
* @param target the "parent" object; the object the proxy
* virtualizes
* @param prop the property called on the Proxy
*/
get: function (target, prop)
{
/* This will return the property on the "parent" object
*/
if (typeof target[prop] !== 'undefined')
return target[prop]
// TODO: implement custom logic
}
}
return new Proxy(this, handler)
}
}
这实质上同时为您提供了与 PHP 的魔术__get
方法和__call
方法相同的功能。至于__call
版本,我们只是返回一个函数供用户输入参数。
证明上述
为了使用它,让我们首先在TODO: implement custom logic
驻留的地方添加一些自定义逻辑:
if (prop === 'helloWorld')
return function () { console.log("Hello, world!") }
else
return function () { console.log("Where art thou, hello world?") }
如果我们继续创建MyProxy
该类的新实例,我们可以触发我们实现的自定义逻辑:
let myProxy = new MyProxy()
myProxy.test()
myProxy.hello()
myProxy.helloWorld()
上面的示例输出:
Where art thou, hello world?
Where art thou, hello world?
Hello, world!
当然,也可以从get
函数返回任何其他类型的值,我们也可以返回字符串或整数。
便于使用; 通过继承使用
为了使其更易于使用,我是否建议将该asProxy
方法包装到另一个类中,然后简单地使用包含该方法的类扩展任何需要“魔术方法”功能的类asProxy
?通过简单地asProxy
从构造函数返回方法,您基本上获得了与 PHP 和 JavaScript 中相同的功能。
当然,它也需要在某种程度上get method
是可编辑的,以便仍然可以从子类处理自定义逻辑。也许通过将闭包发送到然后从函数本身return this.asProxy(() => {})
调用的那个?get
或者甚至可能将get
函数路由到对象get
上存在的方法target
?
但是请记住,这仅适用于 ES6。像 Babel 这样的编译器不能,我引用:
由于 ES5 的限制,不能对代理进行转译或 polyfill。
但是,只要满足此条件,上述解决方案确实可以正常工作。例如,它是Node.js中一个完全可行的选项。