AngularJS: использование сторонних библиотек без отображения глобальной переменной

Каков наилучший способ использования сторонней библиотеки в Angular без раскрытия глобальной переменной?

Например, если я использовал underscore.js, я хочу вставлять _ только в те контроллеры, которые его используют.

angular.module('module').controller(function(_) {
  // _ is injected only into this scope
};

Чтобы получить этот эффект, я видел, как некоторые люди загружают ярлык во всем мире с тегом script, а затем создают такой сервис:

myModule.factory('_', function ($window) {
    return $window._;
});

Однако это все еще загрязняет глобальную область видимости с помощью _.

Есть ли способ Angular регистрировать и вставлять сторонние библиотеки, не вызывая этой проблемы?

Ответы

Ответ 1

Вы ничего не можете сделать о том, как записываются библиотеки сторонних разработчиков, за исключением того, что они разворачивают их и создают вашу собственную версию.

Сторонние библиотеки почти всегда создают такие переменные в глобальной области, и вы упомянете два наиболее часто используемых способа их использования в модуле Angular: путем ввода $window и использования их напрямую или путем создания тонкий service, который обеспечивает объект.

Я бы предпочел последнее в большинстве случаев, потому что он упрощает код в других модулях. Кроме того, на мой взгляд, сервисный подход делает код в ваших контроллерах менее "волшебным" и более отлаживаемым, так как становится ясно, где библиотека, например. _. Переменные, появляющиеся "из воздуха", представляют собой проблему с глобальными переменными.

Библиотека по-прежнему будет "загрязнять" глобальную область видимости, если вы явно не удаляете их из глобальной области видимости, возможно, после получения указателя на них в службе, которая затем может передать ее. Однако я не вижу никакой мотивации для этого. Любые другие попытки, такие как использование службы Angular для фактической загрузки третьей стороны script и ее оценки, каким-то образом препятствующим ее достижению глобальной области, кажутся весьма неэффективными, чрезмерно спроектированными и медленными (как в вычислительной, так и в отношении когда HTTP-запросы запущены).

В противном случае хорошая идея не создавать глобальные переменные, нежели строго необходимые.

Ответ 2

Для сторонних библиотек, поддерживающих функцию noConflict, например Underscore и jQuery - вы можете использовать это для предотвращения глобального загрязнения в Angular factory.

myModule.factory('_', ['$window', function ($window) {
   var underscore = $window._.noConflict();

   return underscore;
}]);

Поскольку все службы в Angular являются одноточечными, это означает, что инжектор использует каждый рецепт не более одного раза для создания объекта. Затем инжектор кэширует ссылку для всех будущих потребностей.

Ответ 3

Майка прав, вы не можете "остановить" модуль от неприятностей. Как только что-то вызывает window.whatever =...

Require.js, хотя и классный, как библиотека/методология определения асинхронного модуля, которая помогает людям, которые создают пакеты, делать это, не опускаясь в глобальное пространство имен. Это не поможет преступникам, но это аккуратно.

http://requirejs.org/

Ответ 4

Поместите сторонние библиотеки в константы angular. Сохраняет ваш код читаемым и чистым, и вы можете вводить их в определенные контроллеры, директивы,... где вы хотите их использовать.

angular
      .module('sampleApp', [])
      .constant('_', window._)
      .constant('$', window.$)

Ответ 5

Я создал инструмент, который создаст angular factory, а не глобальный для всех библиотек, которые поддерживают js. Поскольку большинство библиотек поддерживают require.js, я смог написать функцию, которая имитирует, требует функции "define", но вместо добавления требуемой библиотеки она добавляет ее как angular для инъекций. Это практически plug n' play. Просто включите источник js после jQuery и angular, и вам хорошо идти. Он назвал глобальный инжектор angular и доступен на github. Здесь ссылка: https://github.com/btesser/angular-global-injector