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

16 浏览
0 Comments

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

考虑以下jfiddle http://jsfiddle.net/bchapman26/9uUBU/29/

//angular.js示例,用于比较factory和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");

}​

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

对于非常大的项目(或者通常情况下重用模块),可能会出现名称冲突的风险,这可能很难调试。

是否有一种方法可以为名称添加模块名称前缀,以避免发生名称冲突?

0
0 Comments

在AngularJS中,存在一个命名空间和名称冲突的问题。这个问题的出现主要原因是AngularJS不支持命名空间。在AngularJS中,所有的控制器、过滤器和服务都是在一个全局的单例注入器中注册的,它们的名称是隐式的。这意味着无论模块的名称如何,你只能通过名称来引用这些实体。因此,如果不加以处理,不同模块中的控制器、过滤器和服务的名称可能会发生冲突。

为了解决这个问题,可以使用一种约定来命名模块,使其始终唯一。一种方法是参考其他语言的做法。例如,在Java中,类的“全名”是基于文件名和所在文件夹的名称的。例如,如果你在名为MyArtStuff的文件夹中有一个名为Bitmap.java的Java文件,那么该类的全名将是MyArtStuff.Bitmap。由于AngularJS允许在模块名称中使用点(.)作为分隔符,因此可以使用这种命名约定。例如,如果开发人员在名为“MainPage\Module1.js”的脚本中创建了一个名为“ModuleA”的模块,他们应该将模块命名为“MainPage.Module1.ModuleA”。因为你的应用程序中的每个路径和文件名都是唯一的,所以你的模块名称也将是唯一的。只需让开发人员按照这种约定进行命名即可。

然而,需要注意的是,这种方法无法解决不同模块中具有相同名称的服务、控制器等的问题。但是可以使用类似的方法来解决这个问题,为这些实体的名称添加前缀。

理想情况下,AngularJS会提供命名空间的功能,但目前还没有。因此,我们只能采取开发人员在命名空间出现之前已经使用了40多年的方法,即尽力为元素添加前缀。这个问题并不是新问题,各种语言都存在这个问题,只是新语言使用点符号作为命名空间的分隔符。例如,Java鼓励使用反向域名来确保命名空间的唯一性。像jQuery和Underscore这样的库则尝试使用晦涩的字符。C等没有命名空间的语言使用函数名前缀来区分不同的函数。例如,ObjectiveC核心库函数使用“NS”前缀来区分自己。OpenGL库使用“gl”前缀。只需要应用相同的原则即可。

总之,这个问题是特定于AngularJS的,而不是其他语言或框架。解决方案是使用一种约定来命名模块,这对于解决Brian Chapman提出的问题并没有帮助。在AngularJS中,所有的控制器、服务和过滤器都是根据名称在一个隐式的命名空间中注册的,而不管模块的名称如何。你只能通过名称来引用这些实体。正确的做法是使用一种约定来命名控制器、服务和过滤器,例如为它们的名称添加模块名称的前缀。然而,这种方法容易出错,难以扩展,并且违反了DRY原则。

虽然手动命名空间是冗长、容易出错的,而且降低了可移植性,但这是目前解决这个问题的方法之一。另一种方法是避免同时依赖于具有相同名称的两个模块。这两种方法都揭示了AngularJS中的设计缺陷。

需要注意的是,这个问题不仅存在于AngularJS中,还存在于C和ObjectiveC中,这两种语言也没有命名空间。这些问题都可以通过采取一些措施来解决,尽管这些措施可能是繁琐的、容易出错的,但它们是可以管理的。虽然命名空间是理想的解决方案,但在它出现之前,我们可以采取这些方法来尽量避免冲突的发生。

参考资料:https://github.com/angular/angular.js/issues/2767

0
0 Comments

在AngularJS中,没有命名空间的概念。解决方法之一是使用前缀(另一个解决方法可能是这个!)。请参考以下示例:

// 根应用

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

// 应用1

const app1 = angular.module('app1', []);

app1.controller('app1.main', function($scope) {

$scope.msg = 'App1';

});

// 应用2

const app2 = angular.module('app2', []);

app1.controller('app2.main', function($scope) {

$scope.msg = 'App2';

})

{{msg}}

{{msg}}

在AngularJS中,没有命名空间的概念,这可能会导致模块和名称冲突的问题。为了解决这个问题,可以使用前缀来区分不同的模块。在上述示例中,根应用模块('root-app')依赖于应用1模块('app1')和应用2模块('app2')。每个应用模块都有自己的控制器,例如'app1.main'和'app2.main'。通过在HTML中使用ng-controller指令,可以将控制器与特定的HTML元素关联起来,并在其中使用{{msg}}表达式显示相应的消息。

通过使用前缀来区分不同的模块,可以避免模块和名称冲突的问题。在上述示例中,我们使用了'app1'和'app2'前缀来命名应用模块和控制器。这样,即使在同一个页面中使用了相同的控制器名称(例如'main'),由于它们属于不同的模块,不会发生冲突。这种解决方法可以确保在AngularJS应用中正确地组织和管理模块和控制器,从而避免名称冲突的问题。

0
0 Comments

AngularJS中的模块没有提供任何命名空间的机制,以防止不同模块中的对象发生冲突。这是因为AngularJS应用程序有一个单一的注入器,它保存了所有对象的名称,而不考虑模块名称。

根据AngularJS开发者指南的说法:

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

正如您提到的,当将模块注入主/应用模块时,可能会导致严重的错误。当发生冲突时,错误是静默的,胜者是最后一个注入的模块。

因此,目前没有内置的方法来避免这些冲突。也许将来会有解决方案。对于可能出现这个问题的大型应用程序来说,你是对的,命名约定是你最好的工具。考虑一下属于模块或函数区域的对象是否可以使用一个短前缀。

正如其他帖子中提到的,存在一个“hacky”的解决方案,即在服务的名称前加上它起源的模块,例如module2.MyService。服务名称只是字符串键。依赖的模块--如上面的例子中的myApp--然后定义了MyService在实践中的工作方式。这种方法不是最优的,但是可用的。

目前AngularJS的模块没有提供命名空间来防止不同模块中对象的冲突。解决这个问题的方法是使用命名约定或者在服务的名称前加上模块前缀。尽管这些方法不是最理想的,但是能够解决冲突问题。希望将来能够在AngularJS中提供更好的解决方案。

0