49

考虑以下 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 个模块(模块 1 和模块 2)。module1 和 module2 都定义了一个名为 myService 的服务。当两个模块都导入 myApp 时,这似乎会在 Angular 中的 myService 上产生名称冲突。AngularJs 似乎只是使用了第二个服务定义,而没有警告您可能存在的问题。

非常大的项目(或者只是重用一般的模块)会有名称冲突的风险,这可能很难调试。

有没有办法用模块名称为名称添加前缀,以免发生名称冲突?

4

4 回答 4

63

到目前为止,AngularJS 模块不提供任何类型的命名空间来防止不同模块中的对象之间的冲突。原因是 AngularJS 应用程序有一个注入器,它保存所有对象的名称,而不考虑模块名称。

AngularJS 开发者指南说:

为了管理依赖创建的职责,每个 Angular 应用程序都有一个注入器。注入器是一个服务定位器,负责构建和查找依赖项。

正如您所提到的,将模块注入主/应用程序模块时可能会导致讨厌的错误。当碰撞发生时,它们是沉默的,获胜者由最后注入的模块决定。

所以不,没有避免这些碰撞的内置方法。也许这将在未来发生。对于更容易出现此问题的大型应用程序,您说得对,命名约定是您的最佳工具。考虑属于模块或功能区域的对象是否可以使用短前缀。

于 2013-11-06T18:38:53.303 回答
2

您可以通过使用约定命名模块来避免这种情况,以便它们始终是唯一的。

一种方法是看看其他语言是如何做到的。例如,在 Java 中,类的“全名”基于文件名和它所在的文件夹。例如,如果在 MyArtStuff 文件夹中有一个名为 Bitmap.java 的 Java 文件,则类的全名将成为 MyArtStuff.Bitmap

结果 AngularJS 允许您将点 (.) 作为模块名称的一部分,因此您基本上可以使用名称约定。

例如,如果开发人员在脚本“MainPage\Module1.js”中创建了一个名为“ModuleA”的模块,他们应该将其模块命名为“MainPage.Module1.ModuleA”。因为每个路径和文件名在您的应用程序中都是唯一的,所以您的模块名称将是唯一的。

你只需要让你的开发人员遵循这个约定。

请注意,正如 Rockallite 指出的那样,这对于在多个模块中具有相同名称的服务、控制器等没有帮助。但是您可以使用类似的方法来产生结果,并为这些元素的名称加上前缀。

理想情况下,AngularJS 应该有命名空间,并且在未来它可能会。在那之前,我们能做的最好的事情就是做开发人员在命名空间被发明之前 40 多年一直在做的事情,并尽我们所能为我们的元素添加前缀。

于 2014-09-19T21:03:21.930 回答
0

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>

于 2018-06-07T16:45:38.137 回答
-8

在您希望服务来自的模块上定义您的控制器。

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

于 2012-11-16T00:00:45.857 回答