2017-08-01 61 views
6

我想設置一個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" 

有什麼辦法來建立一個Proxywindow對象,如果不可能,是否有任何棘手的解決方案來實現相同的目標?

+3

不行,因爲你不能使用你的代理替換窗口。 – Bergi

+2

您的代碼只應記錄'proxy.foo ='bar'',而不是'target.foo ='bar''。你發佈的內容是否真的有用? – Bergi

+2

可能的重複[如何檢測當一個全局變量設置爲JavaScript?](https://stackoverflow.com/q/38759116/1048572) – Bergi

回答

1

簡短的回答是沒有。你不能使用這個代理。 修改並重構您的應用程序以擺脫需要執行此類惡作劇總是更好。但我知道有時我們沒有時間做正確的事情。雖然我不建議你這樣做,但你仍然可以對窗口對象進行更改。

你有幾個選擇來做到這一點。 如果你知道你正在尋找的變量列表,你可以使用類似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消耗。 這個檢查代碼並沒有消耗太多,但理論上可以。所以你必須留意它。 在空白頁面的個人資料數據看起來像這樣profile data

記住使用unwatch在Watch.JS或情況下添加一個條件停止的情況下,你使用第二個解決方案中的檢查,一旦他們將完成這項工作

+0

請注意,不能使用Object.keys監視不可枚舉的道具。如果觀看不可枚舉的道具,演出將會更加糟糕。 – estus

+0

@estus這個解決方案已經足夠了,我還沒有使用'getOwnPropertyNames'來減少集合大小來過濾。由於作者只想獲取全局變量聲明,而不是觀察所有窗口屬性。 –

+0

窗口屬性也可以用Object.defineProperty聲明。當預先知道這些變量是什麼時,任務變得更直接。 – estus

0

你實際上沒有試圖觸發窗口代理。你需要做的:

let proxy = new Proxy(window, handler); 
proxy.foo = 'bar'; 

不,你不能做

window = new Proxy(window, handler); 

因爲窗口是不可替代的。

3

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遍歷整個陣列上每次迭代都會導致非常低效的代碼。

forwhile環是要走的路:

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);