Проблема з спробою з'ясувати, в якому середовищі працює ваш код, полягає в тому, що будь-який об’єкт можна змінювати та оголошувати, що робить його майже неможливим з'ясувати, які об'єкти є природними для середовища, а які були змінені програмою.
Однак є кілька хитрощів, які ми можемо використати, щоб точно зрозуміти, в якому середовищі ти знаходишся.
Давайте почнемо з загальноприйнятого рішення, яке використовується в бібліотеці підкреслення:
typeof module !== 'undefined' && module.exports
Ця техніка насправді прекрасна для сервера, тому що, коли requireфункція викликається, вона скидає thisоб'єкт на порожній об'єкт і moduleповторно визначає для вас знову, тобто не потрібно турбуватися про будь-яке зовнішнє підроблення. Поки ваш код завантажений require, ви в безпеці.
Однак це розпадається на веб-переглядачі, оскільки кожен може легко визначити moduleйого, здається, це предмет, який ви шукаєте. З одного боку, це може бути поведінка, яку ви хочете, але це також диктує, які змінні користувач бібліотеки може використовувати в глобальному масштабі. Можливо, хтось хоче використовувати змінну з іменем, moduleяке є exportsвсередині неї, для іншого використання. Навряд чи, але хто ми, щоб судити про те, які змінні може використовуватись хтось інший, лише тому, що інше середовище використовує цю назву змінної?
Підступність полягає в тому, що якщо ми припускаємо, що ваш скрипт завантажується в глобальному масштабі (який він буде, якщо він завантажується через тег скрипту), змінна не може бути зарезервована у зовнішньому закритті, оскільки браузер не дозволяє цього . Тепер пам’ятайте, що у вузлі thisоб’єкт порожній об’єкт, але moduleзмінна все ще доступна. Це тому, що це оголошено у зовнішньому закритті. Тоді ми можемо виправити перевірку підкреслення, додавши додатковий чек:
this.module !== module
При цьому, якщо хтось заявить moduleу глобальній області застосування в браузері, він буде розміщений в thisоб'єкті, що спричинить збій тесту, оскільки this.moduleбуде таким самим об'єктом, що і модуль. У вузлі this.moduleне існує і moduleіснує в межах зовнішнього закриття, тому тест буде успішним, оскільки вони не є рівнозначними.
Таким чином, підсумковий тест:
typeof module !== 'undefined' && this.module !== module
Примітка. Хоча це тепер дозволяє moduleвільно використовувати змінну в глобальному масштабі, все одно можливо обійти її в браузері, створивши нове закриття і оголосивши moduleвсередині нього, а потім завантаживши скрипт у межах цього закриття. У цей момент користувач повністю реплікує середовище вузла і, сподіваємось, знає, що вони роблять, і намагається зробити потрібний стиль вузла. Якщо код викликається в тезі сценарію, він все одно буде захищений від будь-яких нових зовнішніх закриттів.