2017-08-01 23 views
6

Chciałbym skonfigurować Proxy, który ostrzega mnie, gdy nowa właściwość jest zdefiniowana na obiekcie window. (Właściwie chciałbym złapać wszystkie deklaracje zmiennych globalnych)Serwer proxy w oknie

let handler = { 
    defineProperty(target, key, descriptor) { 
     console.log('hey', key); 
     return false; 
    } 
}; 
window = new Proxy(window, handler); 
window.foo = 'bar'; 
// nothing happens 

Powyższy kod działa dla dowolnego obiektu, ale okna:

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" 

Czy istnieje jakiś sposób, aby założyć Proxy na window obiekt, a jeśli nie jest to możliwe, czy istnieje jakieś podchwytliwe rozwiązanie dla osiągnięcia tego samego celu?

+3

Nie, ponieważ nie można zastąpić okno z prokurentem. – Bergi

+2

Twój kod powinien logować się tylko dla 'proxy.foo = 'bar'', a nie dla' target.foo =' bar''. Czy to, co wysłałeś, działa naprawdę? – Bergi

+2

możliwy duplikat [Jak mogę wykryć, kiedy zmienna globalna jest ustawiona w javascript?] (Https://stackoverflow.com/q/38759116/1048572) – Bergi

Odpowiedz

1

Krótka odpowiedź brzmi: nie. Nie możesz użyć do tego proxy. Zawsze lepiej jest zmienić i zreorganizować swoją aplikację, aby pozbyć się konieczności zrobienia takich szantażystów. Ale wiem, że czasami nie mamy czasu, by robić wszystko dobrze. Mimo że nie polecam tego, możesz nadal uzyskać zmiany w obiekcie okna.

Masz kilka opcji, aby to zrobić. Jeśli znasz listę vars, których szukasz, możesz użyć czegoś takiego, jak Watch.JS Zasadniczo jest on w stanie śledzić wszystkie zmiany, ale nie był w stanie sprawić, by działał niezawodnie, więc lepiej jest określić listę

watch(window, ['list', 'of', 'vars'], (prop, action, newVal, oldVal) => { 
    console.log('Property changed', prop, action, newVal, oldVal); 
}, 1); 

Jako alternatywę można stworzyć prosty brudną sprawdzania

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

Ale w przypadku, gdy postanowił udać albo roztworem, trzeba upewnić się, że wszystkie kontrole zatrzyma się, gdy są potrzebne, aby uniknąć wycieków pamięci lub zużycie procesora. Ten kod kontrolny nie zużywa zbyt wiele, ale teoretycznie. Musisz więc mieć na to oko. na pusty danych profilowych strona wygląda tak profile data

i pamiętać o używaniu unwatch w przypadku Watch.JS lub dodać warunek, aby zatrzymać kontrole w przypadku korzystania z drugiego roztworu raz będą one zakończyć pracę

+0

Zauważ, że nieprzeliczalne rekwizyty nie są obserwowane przy użyciu Object.keys. Wydajność będzie znacznie gorsza, gdy obserwowane będą także nieprzeliczalne rekwizyty. – estus

+0

@estus To rozwiązanie jest wystarczające imo i nie użyłem 'getOwnPropertyNames', aby zmniejszyć rozmiar kolekcji do filtrowania. Ponieważ autor chciał po prostu uzyskać deklaracje zmiennych globalnych i nie oglądać wszystkich właściwości okna. –

+0

Właściwości okna można zadeklarować również za pomocą Object.defineProperty. Zadanie staje się znacznie prostsze, gdy wiadomo wcześniej, jakie są te zmienne. – estus

0

Nie próbujesz wyzwolić proxy okna. Trzeba zrobić:

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

I nie, nie można zrobić

window = new Proxy(window, handler); 

jak okno jest niezastąpiona.

3

Proxy jest powolny i nie powinien być używany w miejscach o krytycznym znaczeniu, natomiast window wpływa na całą aplikację i na pewno może być uznany za krytyczny pod względem wydajności.

Jednak właściwość window to read-only, tj. Nie jest konfigurowalna i nie ma ustawionego akcesora, nie można jej zastąpić proxy.

Alternatywą Proxy które mogą szpiegować window zmian jest Firefox specyficzny sposób watch, może on być stosowany w skryptach, które działają w Firefoksie (na przykład rozszerzenia), ale nie nigdzie indziej. Specyficzne dla V8: Object.observe nie można było oglądać zgodnie z projektem, a ponadto zostało ono usunięte z przeglądarki Chrome i innych przeglądarek V8.

Generalnie można to osiągnąć poprzez odpytywanie window właściwości:

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

Jeśli kod ten ma być stosowany w produkcji, powinny być zoptymalizowane, ponieważ filter jest stosunkowo powolny, a indexOf przemierza całą tablicę na każda iteracja skutkuje bardzo nieefektywnym kodem.

Raw for lub while pętla jest do zrobienia:

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