Столкновение модулей и пространства имен / имен в AngularJS

рассмотрим следующий jfiddle http://jsfiddle.net/bchapman26/9uUBU/29/

//angular.js example for factory vs service
var app = angular.module('myApp', ['module1', 'module2']);

var service1module = angular.module('module1', []);

service1module.factory('myService', function() {
    return {
        sayHello: function(text) {
            return "Service1 says "Hello " + text + """;
        },
        sayGoodbye: function(text) {
            return "Service1 says "Goodbye " + text + """;
        }
    };
});

var service2module = angular.module('module2', []);

service2module.factory('myService', function() {
    return {
        sayHello: function(text) {
            return "Service2 says "Hello " + text + """;
        },
        sayGoodbye: function(text) {
            return "Service2 says "Goodbye " + text + """;
        }
    };
});

function HelloCtrl($scope, myService) {
    $scope.fromService1 = myService.sayHello("World");
}

function GoodbyeCtrl($scope, myService) {
    $scope.fromService2 = myService.sayGoodbye("World");
}​

У меня есть 2 модуля (module1 и module2). И module1, и module2 определяют службу с именем myService. Это создает столкновение имен на myService в Angular, когда оба модуля импортируются в myApp. Похоже, AngularJs просто использует второе определение службы без предупреждения о возможной проблеме.

очень большие проекты (или просто повторное использование модули в целом) будет иметь риск столкновения имен, что может быть трудно отладить.

есть ли способ префиксировать имена с именем модуля, чтобы столкновения имен не происходили?

4 ответов


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

на Руководство Для Разработчиков AngularJS говорит:

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

Как вы уже упоминали, неприятные ошибки могут возникнуть при инъекции модулей в ваш основной/app модуль. Когда происходят столкновения, они молчат, и победитель определяется тем, какой был последний введенный модуль.

Так что нет, нет встроенного способа избежать этих столкновений. Возможно, это произойдет в будущем. Для больших приложений, где эта проблема становится более вероятной, вы правы, что соглашения об именах - ваш лучший инструмент. Рассмотрим, могут ли объекты, принадлежащие модулю или области функций, использовать короткий префикс.


вы можете избежать этой ситуации, используя соглашение, чтобы назвать свои модули так, чтобы они всегда были уникальными.

один из подходов-посмотреть, как это делают другие языки. Например, в Java "полное имя" класса основано на имени файла и папки, в которой он находится. Например, если у вас есть файл Java с именем Bitmap.java в папке MyArtStuff полное имя класса будет MyArtStuff.Bitmap

оказывается, AngularJS позволяет вам иметь точки (.) в рамках ваше имя модуля, чтобы вы могли по существу использовать соглашение об имени.

например, если разработчик создает модуль под названием "ModuleA "в скрипте" MainPage\Module1.js "они должны назвать свой модуль" MainPage.Модуль1.ModuleA". Поскольку каждый путь и имя файла уникальны в вашем приложении, ваше имя модуля будет уникальным.

вам просто нужно заставить своих разработчиков следовать этой конвенции.

Примечание, поскольку Rockallite указывает, что это не поможет с услугами, контроллеры и т. д., имеющие одинаковое имя в нескольких модулях. Но вы можете использовать аналогичный подход для этого и префикса имен этих элементов.

В идеале AngularJS будет иметь пространства имен, и в будущем это может быть. До тех пор лучшее, что мы можем сделать, - это сделать то, что разработчики делали более 40 лет, прежде чем были изобретены пространства имен, и префикс наших элементов.


к сожалению, нет namespacing на AngularJS. Одним из решений является использование prefix (другое решение может быть этой!). Рассмотрим следующий пример:

// root app
const rootApp = angular.module('root-app', ['app1', 'app2']);

// app 1
const app1 = angular.module('app1', []);
app1.controller('app1.main', function($scope) {
  $scope.msg = 'App1';
});

// app2
const app2 = angular.module('app2', []);
app1.controller('app2.main', function($scope) {
  $scope.msg = 'App2';
})
<!-- angularjs@1.7.0 -->
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.7.0/angular.min.js"></script>

<!-- root app -->
<div ng-app="root-app">

  <!-- app 1 -->
  <div ng-controller="app1.main">
    {{msg}}
  </div>

  <!-- app 2 -->
  <div ng-controller="app2.main">
    {{msg}}
  </div>

</div>

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

service2Module.controller("ServiceTwoCtrl", function(myService, $scope) {});