代理窗口
我想设置一个Proxy
,它在window
对象上定义一个新属性时会发出警告。 (其实我想抓住所有的全局变量声明)代理窗口
let handler = {
defineProperty(target, key, descriptor) {
console.log('hey', key);
return false;
}
};
window = new Proxy(window, handler);
window.foo = 'bar';
// nothing happens
上面的代码适用于任何对象,但窗口:
let handler = {
defineProperty(target, key, descriptor) {
console.log('hey', key);
return false;
}
};
let target = {};
target = new Proxy(target, handler);
target.foo = 'bar';
// console: "hey bar"
有什么办法来建立一个Proxy
上window
对象,如果不可能,是否有任何棘手的解决方案来实现相同的目标?
简短的回答是没有。你不能使用这个代理。 修改并重构您的应用程序以摆脱需要执行此类恶作剧总是更好。但我知道有时我们没有时间做正确的事情。虽然我不建议你这样做,但你仍然可以对窗口对象进行更改。
你有几个选择来做到这一点。 如果你知道你正在寻找的变量列表,你可以使用类似Watch.JS的东西基本上它能够跟踪所有的变化,但我无法使它可靠地工作,所以最好指定一个列表
watch(window, ['list', 'of', 'vars'], (prop, action, newVal, oldVal) => {
console.log('Property changed', prop, action, newVal, oldVal);
}, 1);
作为替代方案,您可以创建一个简单的脏检查
let props = Object.keys(window);
const check =() => {
const currentProps = Object.keys(window);
const newProps = currentProps.filter(item => props.indexOf(item) === -1);
if (newProps.length) {
console.log('Added these properties', newProps);
props = currentProps;
}
requestAnimationFrame(check);
};
requestAnimationFrame(check);
,但如果你决定去与任何一个解决方案,你必须确保在需要的时候,以避免内存泄漏所有的检查将停止或CPU消耗。 这个检查代码并没有消耗太多,但理论上可以。所以你必须留意它。 在空白页面的个人资料数据看起来像这样
记住使用unwatch
在Watch.JS或情况下添加一个条件停止的情况下,你使用第二个解决方案中的检查,一旦他们将完成这项工作
你实际上没有试图触发窗口代理。你需要做的:
let proxy = new Proxy(window, handler);
proxy.foo = 'bar';
不,你不能做
window = new Proxy(window, handler);
因为窗口是不可替代的。
Proxy
速度很慢,不应在性能关键的地方使用,而window
会影响整个应用程序,当然也可能会被视为性能至关重要。
但window
属性是read-only,即它是不可配置的,并且没有set访问器,它不能被替换为代理。
的替代Proxy
可以在window
变化窥探是火狐特异性watch
方法,它可以在在Firefox(例如扩展),而不是任何其他地方运行脚本中使用。 V8特定的Object.observe
无法通过设计观察到window
,而且它已从Chrome和其他V8浏览器中删除。
通常,这可以通过轮询window
属性来实现:
let oldProps;
setInterval(() => {
console.time('Polling window');
let newProps = Object.getOwnPropertyNames(window);
if (oldProps) {
let addedProps = newProps.filter(prop => oldProps.indexOf(prop) < 0);
console.log('Added props', addedProps);
}
oldProps = newProps;
console.timeEnd('Polling window');
}, 500);
如果该代码应该在生产中使用,它应该被优化,因为filter
相对较慢,并indexOf
遍历整个阵列上每次迭代都会导致非常低效的代码。
生for
或while
环是要走的路:
let oldProps;
setInterval(() => {
console.time('Polling window');
let newProps = Object.getOwnPropertyNames(window).sort();
if (oldProps) {
for (let oldI = 0, newI = 0; oldI < oldProps.length || newI < newProps.length; oldI++, newI++) {
let oldProp = oldProps[oldI];
let newProp = newProps[newI];
if (newProp > oldProp || newProp === undefined) {
newI--;
console.log('Removed prop', oldProp);
} else if (newProp < oldProp || oldProp === undefined) {
oldI--;
console.log('Added prop', newProp);
}
}
}
oldProps = newProps;
console.timeEnd('Polling window');
}, 500);
不行,因为你不能使用你的代理替换窗口。 – Bergi
您的代码只应记录'proxy.foo ='bar'',而不是'target.foo ='bar''。你发布的内容是否真的有用? – Bergi
可能的重复[如何检测当一个全局变量设置为JavaScript?](https://stackoverflow.com/q/38759116/1048572) – Bergi