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 requirewywoływana jest funkcja, resetuje thisobiekt do pustego obiektu i ponownie definiuje moduledla 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ć, moduleaby 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ę exportsw 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 thisobiekt jest pustym obiektem, ale modulezmienna 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 modulew zasięgu globalnym w przeglądarce, zostanie on umieszczony w thisobiekcie, co spowoduje niepowodzenie testu, ponieważ this.modulebędzie to ten sam obiekt co module. W węźle this.modulenie istnieje i moduleistnieje 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 moduleswobodne używanie zmiennej w zakresie globalnym, nadal można to ominąć w przeglądarce, tworząc nowe zamknięcie i deklarując modulew 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.