Problem z próbą ustalenia, w jakim środowisku działa twój kod, polega na tym, że każdy obiekt można zmodyfikować i zadeklarować, co sprawia, że ustalenie, które obiekty są natywne dla środowiska, a które zostały zmodyfikowane przez program, jest prawie niemożliwe.
Jest jednak kilka sztuczek, których możemy użyć, aby z całą pewnością dowiedzieć się, w jakim środowisku się znajdujesz.
Zacznijmy od ogólnie przyjętego rozwiązania używanego w bibliotece podkreślników:
typeof module !== 'undefined' && module.exports
Ta technika jest w rzeczywistości idealna dla serwera, ponieważ gdy require
wywoływana jest funkcja, resetuje this
obiekt do pustego obiektu i ponownie definiuje module
dla Ciebie, co oznacza, że nie musisz się martwić o jakiekolwiek ingerencje z zewnątrz. Dopóki Twój kod jest załadowany require
, jesteś bezpieczny.
Jednak to się rozpada w przeglądarce, ponieważ każdy może łatwo zdefiniować, module
aby wyglądał, jakby to był obiekt, którego szukasz. Z jednej strony może to być zachowanie, które chcesz, ale określa również, jakich zmiennych użytkownik biblioteki może używać w zakresie globalnym. Może ktoś chce użyć zmiennej z nazwą module
, która się exports
w niej znajduje, do innego użytku. Jest to mało prawdopodobne, ale kim jesteśmy, aby oceniać, jakich zmiennych może używać ktoś inny, tylko dlatego, że inne środowisko używa tej nazwy zmiennej?
Sztuczka polega jednak na tym, że jeśli założymy, że twój skrypt jest ładowany w zasięgu globalnym (co będzie, jeśli będzie ładowany przez tag skryptu), zmienna nie może być zarezerwowana w zewnętrznym zamknięciu, ponieważ przeglądarka na to nie pozwala . Teraz pamiętaj, że w węźle this
obiekt jest pustym obiektem, ale module
zmienna jest nadal dostępna. To dlatego, że jest zadeklarowany w zewnętrznym zamknięciu. Więc możemy następnie naprawić kontrolę podkreślenia, dodając dodatkową kontrolę:
this.module !== module
Dzięki temu, jeśli ktoś zadeklaruje module
w zasięgu globalnym w przeglądarce, zostanie on umieszczony w this
obiekcie, co spowoduje niepowodzenie testu, ponieważ this.module
będzie to ten sam obiekt co module. W węźle this.module
nie istnieje i module
istnieje w zewnętrznym zamknięciu, więc test powiedzie się, ponieważ nie są równoważne.
Tak więc ostateczny test to:
typeof module !== 'undefined' && this.module !== module
Uwaga: Chociaż pozwala to teraz na module
swobodne używanie zmiennej w zakresie globalnym, nadal można to ominąć w przeglądarce, tworząc nowe zamknięcie i deklarując module
w nim, a następnie ładując skrypt w tym zamknięciu. W tym momencie użytkownik w pełni replikuje środowisko węzłów i miejmy nadzieję, że wie, co robi i próbuje spełnić wymagania stylu węzła. Jeśli kod jest wywoływany w tagu skryptu, nadal będzie zabezpieczony przed nowymi zewnętrznymi zamknięciami.