Javascript 打字稿-she';我们必须拥有它吗?(其中it==全局范围)
我正在将Angular应用程序转换为使用TypeScript,但这是一个一般的TypeScript问题,与Angular无关。 角度js文件如下所示:Javascript 打字稿-she';我们必须拥有它吗?(其中it==全局范围),javascript,angularjs,scope,typescript,Javascript,Angularjs,Scope,Typescript,我正在将Angular应用程序转换为使用TypeScript,但这是一个一般的TypeScript问题,与Angular无关。 角度js文件如下所示: (function () { var app = angular.module('myModule', []); app.controller('myController', ['$scope', function ($scope) { $scope.myNewProperty = "Bob"; } ]);
(function () {
var app = angular.module('myModule', []);
app.controller('myController', ['$scope',
function ($scope) {
$scope.myNewProperty = "Bob";
}
]);
})();
我已将其转换为可爱的TypeScript类语法:
class myController {
constructor($scope) {
$scope.myNewProperty = "Bob";
}
}
angular.module('myModule', []).controller("myController", myController);
除了生成的JS没有按照JS模块模式进行包装(即在外部匿名函数中),所有工作正常:
所以myController现在是全球性的。如果我将该类放入一个TypeScript模块中,那么js将以模块名作为全局变量生成:
var TsModule;
(function (TsModule) {
var myController = (function () {
app.controller('myController', ['$scope',
function ($scope) {
$scope.myNewProperty = "Bob";
}
]);
})();
var app = angular.module('myModule', []);
})(TsModule || (TsModule = {}));
如何阻止TypeScript以这种方式污染全局范围?我只想把它包装在一个漂亮的局部范围内。
我在别处看到它说“只需回到旧的JS语法”(即没有TypeScript类)。
但是我们使用TypeScript/is/的全部要点是类语法。TypeScript是否与任何(明智的)知道不走向全局的JS程序员不一致?快速更新
在最新版本的TypeScript中,您可以在IIFE中嵌套一个类:
(() => {
class Example {
}
})();
结果是:
(function () {
var Example = (function () {
function Example() {
}
return Example;
}());
})();
原始答案
您可以避免使用AMD或CommonJS等模块模式添加到全局范围。当您使用其中任何一个时,每个TypeScript文件都被视为一个外部模块,不在全局范围内
本例出于本例的目的删除了Angular,但尽管RequireJS将define
方法添加到global,但您的代码都不在此范围内
MyModule.ts
export class myController {
constructor($scope) {
$scope.myNewProperty = "Bob";
}
}
app.ts
import MyModule = require('MyModule');
var controller = new MyModule.myController('');
HTML
或者。。。如你所知。。。如果您愿意,您仍然可以使用已经在使用的JavaScript来实现这一切-您仍然可以获得自动完成和类型检查,这是即使您没有获得类的主要好处。您可以简单地将类包装在
模块中。
模块本身是全局的,但如果不导出类,就不必担心用单个模块名污染全局范围
因此,这个类型脚本:
module MyModule {
class MyClass {
constructor(){}
}
}
(function () {
class MyController {
static $inject = ['$scope'];
contructor($scope: ng.IScope & { myNewProperty: string }) {
$scope.myNewProperty = 'Bob';
}
}
angular.module('myModule', [])
.controller('MyController', MyController);
})();
将生成以下JS:
var MyModule;
(function (MyModule) {
var MyClass = (function () {
function MyClass() {
}
return MyClass;
})();
})(MyModule || (MyModule = {}));
乔希是对的。使用模块。同样,使用grunt或gulp uglifyer可能是一个好主意,它可以选择在构建时将整个应用程序封装在一个闭包中 这不是对你问题的回答,而是一个建议
在侧面注释中,考虑控制器
的语法module myModule {
// We export the class so that we can access its interface in tests.
// The build time gulp or grunt uglify will wrap our app in a closure
// so that none of these exports will be available outside the app.
export class MyController {
myNewProperty = "bob";
// Next we will use Angulars $inject annotation to inject a service
// into our controller. We will make this private so that it can be
// used internally.
static $inject = ['someService'];
constructor(private someService: ng.ISomeService) {}
// we can access our class members using 'this'
doSomething() {
this.someService.doSomething(this.myNewProperty);
}
}
angular.module('app').controller('MyController', MyController);
}
与此语法一起使用的是controllerAs语法 就像在JavaScript中一样,通过将声明包装在立即调用的函数表达式中,可以完全避免名称空间污染 因此,原始JavaScript:
(function () {
var app = angular.module('myModule', []);
app.controller('myController', ['$scope',
function ($scope) {
$scope.myNewProperty = "Bob";
}
]);
})();
成为以下类型脚本:
module MyModule {
class MyClass {
constructor(){}
}
}
(function () {
class MyController {
static $inject = ['$scope'];
contructor($scope: ng.IScope & { myNewProperty: string }) {
$scope.myNewProperty = 'Bob';
}
}
angular.module('myModule', [])
.controller('MyController', MyController);
})();
请注意,这不会在周围的范围中引入任何名称。实际上,原始JavaScript是完全有效的TypeScript,但它没有利用TypeScript。
还请注意,我对样式进行了轻微的编辑
无论如何,如果您没有使用带有模块加载器的模块,如RequireJS、SystemJS或您拥有的其他模块,那么您仍然可以通过遵循久经考验的IIFE模式来避免名称空间污染。这是我的建议。我已经有一段时间没有使用TypeScript了,所以我可能会停止使用它,但是您是否尝试过在立即调用的lambda函数中包装上述TypeScript代码<代码>(()=>{//code here…})()代码>我感到很沮丧,但是为所有文件使用一个定义良好的模块名几乎不会影响全局范围。它将在全局范围内创建一个变量,即使这样,如果您不导出类,那么它也永远不会超过一个空对象。这是一个相当小的问题。仅供参考(你可能已经知道)类表达式将在TS中出现,这将允许它们在IIFE中使用。此外,这段关于TypeScript中模块模式的视频(我制作)可能对您有用:@AluanHaddad-是的,现在可以了。这在2014年12月是不允许的。嗨,谢谢回复。我正在编辑我的问题,以便在我的行中展开“如果我将类放在TypeScript模块中,那么js将以模块名称作为全局变量生成:”-编辑是生成的代码,与您的代码几乎相同。关键是(在您的示例中)var MyModule现在是全局的。我们已将控制器全局替换为模块全局。如果另一个javascript库有一个MyModule全局变量,那么混乱就会接踵而至@user603563-不完全是因为它使用的是显示模块模式。因此,如果模块已经存在,它不会重新定义该模块。只有当你在模块中添加了一些你期望外部可用的东西时,混乱才会随之而来。在这种情况下,您没有将类添加到模块中,因此不会发生冲突。这只是一个简单的过程。我刚刚回到我的JS引用,是的,我再次了解到,与使用核函数来创建以前声明的MyObject不同,MyObject的后续变量只会添加到现有对象中(或者,如果像本例一样,没有对MyObject进行任何操作,则不会更改)。好的(尽管我很讨厌,因为它不能回答TypeScript是否可以完全避免污染全局范围)我会将此标记为答案,因为有了这些注释,这确实充分解释了为什么它没有我想象的那么重要…@AluanHaddad-我理解,但问题是专门关于使用TypeScript语法的。在撰写本文时,规范的做法是创建一个不带导出的
模块
,这是正确的创建了一个闭包。从那时起,情况发生了很大变化,内部模块是使用名称空间创建的。从长远来看,我可能会认为使用reales6
模块是一个更好的选择。@Josh yes es6模块更可取。不管问题是如何做到这一点而不污染名称空间。名称空间只是内部模块的一个新关键字。问题的关键是,对于所问的问题,有一个非常简单的答案,而不是您给出的答案,事实上,没有人给出
(function () {
class MyController {
static $inject = ['$scope'];
contructor($scope: ng.IScope & { myNewProperty: string }) {
$scope.myNewProperty = 'Bob';
}
}
angular.module('myModule', [])
.controller('MyController', MyController);
})();