Ответ 1
ПРИМЕЧАНИЕ. Этот вопрос состоял из двух частей, но поскольку название было "Обнаружение среды: node.js или браузер" - я сначала займусь этой частью, потому что, по-моему, многие люди приходят сюда, чтобы найти ответ к тому, что. Отдельный вопрос может быть в порядке.
В переменных JavaScript могут быть переопределены внутренние области, поэтому, предполагая, что среда не создала переменные, называемые процессом, глобальные или окна могут легко завершиться неудачей, например, если вы используете модуль node.js jsdom, Пример использования API
var window = doc.defaultView;
После чего обнаружение среды, основанной на существовании переменной window
, будет систематически отказываться от любого модуля, работающего под этой областью. С той же логикой любой код на основе браузера может легко перезаписать global
или process
, поскольку они не являются зарезервированными переменными в этой среде.
К счастью, существует способ потребовать глобальную область и проверить, что это такое - если вы создаете новую функцию с помощью конструктора new Function()
, область выполнения this
привязана к глобальной области, и вы можете сравнить глобальный охват непосредственно к ожидаемому значению. *)
Итак, чтобы создать функцию, проверьте, будет ли глобальная область "окном"
var isBrowser=new Function("try {return this===window;}catch(e){ return false;}");
// tests if global scope is binded to window
if(isBrowser()) console.log("running under browser");
И функция, чтобы проверить, привязана ли глобальная привязка к глобальному, будет
var isNode=new Function("try {return this===global;}catch(e){return false;}");
// tests if global scope is binded to "global"
if(isNode()) console.log("running under node.js");
попытка... catch -part убедится, что если переменная не определена, возвращается false
.
isNode()
также может сравнить this.process.title==="node"
или некоторую другую глобальную переменную области видимости внутри node.js, если вы это сделаете, но по сравнению с глобальным должно быть достаточно на практике.
ПРИМЕЧАНИЕ: определение рабочей среды не рекомендуется. Однако он может быть полезен в конкретной среде, такой как среда разработки и тестирования, которая имеет некоторые известные характеристики для глобальной области.
Теперь - вторая часть ответа. после обнаружения среды, вы можете выбрать, какую стратегию на основе среды вы хотите использовать (если есть), чтобы привязать переменную, которая является глобальной "к вашему приложению.
Рекомендуемая стратегия здесь, на мой взгляд, заключалась бы в использовании шаблона singleton для привязки ваших настроек внутри класса. В SO
есть хороший список альтернатив,Простейший/Самый чистый способ реализовать singleton в JavaScript?
Итак, может получиться, если вам не нужна "глобальная" переменная, и вам вообще не требуется обнаружение среды, просто используйте шаблон singleton для определения модуля, который сохранит значения для вас. Хорошо, можно утверждать, что сам модуль является глобальной переменной, которая на самом деле в JavaScript, но по крайней мере теоретически это выглядит немного более чистым способом.
*) https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function
Примечание. Функции, созданные с помощью конструктора Function, не создают закрытие их контекстов создания; они всегда создаются в глобальный охват. При их запуске они смогут получить доступ их собственные локальные переменные и глобальные, а не те из них в котором был вызван конструктор Function.