AngularJS中的模块和名称空间/名称冲突

AngularJS中的模块和名称空间/名称冲突,angularjs,namespaces,collision,angularjs-module,Angularjs,Namespaces,Collision,Angularjs Module,考虑以下jfiddle 我有两个模块(模块1和模块2)。模块1和模块2都定义了一个名为myService的服务。当两个模块都导入myApp时,这似乎会在Angular中的myService上创建名称冲突。AngularJs似乎只是使用了第二个服务定义,没有警告您可能出现的问题 非常大的项目(或者通常只是重用模块)会有名称冲突的风险,这可能很难调试 有没有一种方法可以在名称前面加上模块名,这样就不会发生名称冲突 在您希望服务来自的模块上定义控制器 service2Module.controller

考虑以下jfiddle

我有两个模块(模块1和模块2)。模块1和模块2都定义了一个名为myService的服务。当两个模块都导入myApp时,这似乎会在Angular中的myService上创建名称冲突。AngularJs似乎只是使用了第二个服务定义,没有警告您可能出现的问题

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


有没有一种方法可以在名称前面加上模块名,这样就不会发生名称冲突

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


service2Module.controller(“serviceTowCtrl”,函数(myService,$scope){})

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

报告说:

为了管理依赖项创建的责任,每个 应用程序有一个注入器。喷油器是一个维修定位器 负责构建和查找依赖项

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


所以不,没有一种内在的方式来避免这些碰撞。也许这会在将来发生。对于更容易出现此问题的大型应用程序,命名约定是最好的工具,这是正确的。考虑属于模块或函数区域的对象是否可以使用短前缀。 您可以通过使用约定来命名模块以使其始终唯一来避免这种情况

一种方法是研究其他语言是如何做到这一点的。例如,在Java中,类的“全名”基于文件名及其所在的文件夹。例如,如果在MyArtStuff文件夹中有一个名为Bitmap.Java的Java文件,则该类的全名将是MyArtStuff.Bitmap

事实证明,AngularJS允许您将点(.)作为模块名称的一部分,这样您就可以基本上使用名称约定

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

你只需要让你的开发者遵循这个惯例

注:正如Rockallite指出的,这对多个模块中具有相同名称的服务、控制器等没有帮助。但是,您可以使用类似的方法来实现这一点,并在这些元素的名称前加前缀


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

不幸的是,AngularJS中没有
名称空间。一种解决方案是使用
前缀
(另一种解决方案可能是!)。请参见以下示例:

//根应用程序
const rootApp=angular.module('root-app',['app1','app2']);
//应用程序1
常量app1=角度模块('app1',[]);
app1.controller('app1.main',函数($scope){
$scope.msg='App1';
});
//附件2
常量app2=角度模块('app2',[]);
app1.controller('app2.main',函数($scope){
$scope.msg='App2';
})

{{msg}}
{{msg}}

更新:我发现了一种可能的解决方法,将命名约定应用于传递到di系统的服务名称。但是,我的主要问题仍然是:是否有一种本地方法来避免上面提到的名称冲突?这似乎是一个问题,尤其是当您考虑到第三方组件的潜在用途时。我提出了一个问题。我认为这不是一个问题(实际上是一个特性和设计),因为它对于测试和重写行为很有用。名称空间或使用命名约定是一种方法。在使用此建议后,这似乎对解决服务上的名称冲突没有任何作用。Hmm。。为什么你需要两个模块名为“AdyJuxLin?”反过来说,你如何发现你有一个名字冲突?@安德鲁乔斯林考虑一个应用程序,你不控制在哪里开发所有的模块。一些插件类型的架构,其中多个团队构建组件。@AndrewJoslin如果您的应用程序依赖于第三方模块,如何避免您自己的模块和它们的模块(以及所有这些第三方模块)之间的控制器/过滤器/服务名称冲突?Jim,这很好地总结了我的问题。感谢您的回复。正如在其他帖子中提到的,一个“黑客”解决方案是通过在服务名称前加上发起它的模块而存在的,例如
module2.MyService
。毕竟,服务名称只是字符串键。上述示例中的从属模块--
myApp
将定义
MyService
在实践中的工作方式。次优但可用。这不是关于模块名称,而是关于服务/过滤器/控制器等-在这些名称中,我真的不会使用点表示法(特别是不使用ng注释)…这不是关于模块名称冲突。这是关于不同模块中的控制器/过滤器/服务名称冲突(特别是来自第三方的冲突)。由于您直接使用控制器/过滤器/服务的名称引用它们,并且没有任何名称空间,因此您对模块名称所做的任何操作都没有任何帮助。@Rockallite防止冲突只意味着名称必须是唯一的。我不是新问题。它存在于所有语言中,较新的语言使用带有点符号的名称空间。Java鼓励
//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");
}​