您可以使用Object.defineProperty 和Object.observe 来模拟代理。我开始想知道 polyfill 可以支持多少功能,所以我编写了一个实现(你可以在 gist.github.com/mailmindlin/640e9d707ae3bd666d70 看到它)。
我能够模拟 Proxy 的所有不依赖于运算符重载的功能,这在 JavaScript 中是不可能的。
但是,您可以让get、set 和其他一些工作。您可以使用 getter 和 setter 来镜像目标对象的属性:
for (var property in target)
Object.defineProperty(proxy, property, {
get: function() {
if ('get' in handler)
return handler.get(target, property, proxy);
else
return target[property];
},
set: function(value) {
if ('set' in handler)
handler.set(target, property, value, proxy);
else
target[property] = value;
}});
唯一的问题是 getter 和 setter 只适用于在代理初始化时为目标定义的属性,delete 运算符将不起作用(如果您删除目标上的属性对象,代理仍会将其枚举为属性;如果您删除代理上的属性,则该对象不会发生任何事情。
要解决这个问题,您可以使用Object.observe,在对任一对象进行任何更改时都会调用它。对caniuse.com 的快速检查表明 Object.observe 在 Chrome 和 Opera 上可用。如果您确实需要在其他浏览器上支持 Proxy,您可以轮询 target 和 proxy 对象,以检查是否已创建或销毁任何属性:
var oldKeys = Object.keys(proxy);
setInterval(function() {
var keys = Object.keys(proxy);
for(var i in keys)
if(!oldKeys.includes(keys[i]))
//Trigger code for a new property added
for(var i in oldKeys)
if(!keys.includes(oldKeys[i]))
//trigger code for a deleted property
oldKeys = keys;
//repeat for target object
}, 100);
如果您迫切需要代理的更多功能,可以尝试覆盖 Object.defineProperty 和 Object.getOwnPropertyDescriptor 等方法,但这可能会导致与其他脚本的兼容性问题,具体取决于您的操作方式。
简而言之,您可以使用 Proxy 和 polyfill 完成大部分您可能需要的事情。至于谷歌将它添加到他们的浏览器,我不知道。它显然曾经是 V8 引擎的一部分,但由于安全问题(没有人详细说明)而被删除,据我所知 this thread。