Проблема с попыткой выяснить, в какой среде работает ваш код, состоит в том, что любой объект может быть изменен и объявлен, что делает практически невозможным выяснение того, какие объекты являются родными для среды, а какие были изменены программой.
Однако есть несколько приемов, которые мы можем использовать, чтобы точно определить, в какой среде вы находитесь.
Давайте начнем с общепринятого решения, которое используется в библиотеке подчеркивания:
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в нем, а затем загрузив скрипт в этом закрытии. В этот момент пользователь полностью реплицирует среду узла и, надеюсь, знает, что он делает, и пытается выполнить требования стиля узла. Если код вызывается в теге скрипта, он все равно будет защищен от любых новых внешних замыканий.