Что происходит, когда я назначаю наблюдателя / прокси, который все портит.
Проблема в том, что свойство width
на самом деле является getter в Screen.prototype
. Это не обычное значение для window.screen
:
console.log(window.screen.width);
console.log(window.screen.hasOwnProperty('width'));
// The property exists on the prototype instead, and is a getter:
const descriptor = Object.getOwnPropertyDescriptor(Screen.prototype, 'width');
console.log(descriptor);
Если бы свойство width
было обычным свойством, состоящим из простого значения, которое было установлено браузером с помощью eval
ing
window.screen.width = 1500
тогда будет работать прокси или полифилл Object.watch
, потому что вы сможете перехватить присвоение свойству .width
. Вот почему вы видите это после назначения своего собственного установщика на window.screen.width
:
Выполните screen.width = 100;
и обратите внимание, что привет зарегистрирован, и screen.width установлен на 100
Показывает hello
- вы вызываете установщик, который ранее был назначен свойству screen
window
. Напротив, поскольку встроенное встроенное свойство не является простым значением, которое присваивается браузером, ваш hello
не регистрируется при изменении экрана. Ситуация бит похожа на то, что происходит в следующем примере:
const obj = (() => {
let privateVal = 'propOriginal';
// privateVal changes after 500ms:
setTimeout(() => {
console.log('Changing privateVal to propChanged');
privateVal = 'propChanged';
}, 500);
// Return an object which has a getter, which returns privateProp:
return {
get privateProp() {
return privateVal;
}
};
})();
// At this point, if one only has a reference to `obj`,
// there is no real way to watch for changes to privateVal:
console.log(obj.privateProp);
// Assigning a custom setter to obj.privateProp
// will only result in observing attempted assignments to obj.privateProp
// but will not be able to observe the change to privateVal:
Object.defineProperty(obj, 'privateProp', { set(newVal) {
console.log('Observed change: new value is ' + newVal);
}});
setTimeout(() => {
obj.privateProp = 1000;
}, 2500);
Как видите, функция установки, добавленная к obj
во внешней области видимости, не может зафиксировать изменение в privateVal
. Это не точно , что происходит с window.screen
, но это похоже; у вас нет доступа к базовой структуре кода, которая приводит к изменению значения, возвращаемого при вызове встроенного метода получения.
Встроенная функция получения в screen
состоит из собственного кода - это означает, что это не обычная функция Javascript. Функции, составленные из собственного кода, всегда являются функциями, предоставляемыми браузером (или любой средой, в которой выполняется код); они часто не могут быть эмулированы никакими функциями Javascript, которые вы пишете сами. Например, only объект window.history
может выполнять исторические действия, такие как history.back()
; если window.history
перезаписывается, и у вас нет сохраненной ссылки на него или любые другие объекты history
, нет способа написать собственную функцию, которая может выполнять history.back()
, потому что .back()
вызывает привилегированный нативный код , который требует интерфейса между видимым Javascript и механизмом браузера.
Аналогично, встроенный window.screen
геттер, при вызове, возвращает значение , не наблюдаемое напрямую простым Javascript. Без опроса единственный другой способ следить за изменениями - прослушивать событие resize
, как описано в другом ответе. (Это resize
событие, аналогичное базовому значению, возвращаемому window.screen
, управляется внутренними элементами браузера , иначе не наблюдается.)
Если событие resize
не запускается в ответ на изменение разрешения - например, если окно браузера уже достаточно мало, чтобы изменение не требовалось для меньшего разрешения, - изменение разрешения не приводит в любом случае увольнение означает, что, к сожалению, нет способа его прослушать, кроме опроса. ( Вы можете попробовать это сами , не похоже, что другие события запускаются при изменении разрешения)
Возможно, можно написать (или настроить) движок браузера, который прослушивает изменение разрешения ОС и отправляет событие Javascript при обнаружении, но для этого потребуются знания далеко за пределами Javascript - не стесняйтесь просматривать Источник Chromium код для деталей, но он довольно сложный, и, вероятно, непрозрачный, без опыта в используемых языках.