询价QQ:15208189    咨询热线:13520752365

联系我们 /contact

letou国际米兰|网站

电 话:13520752365

传 真:010-58043628

Q Q:15208189

邮 箱:15208189@qq.com

联 系 人:苏朋朋

letou国际米兰:北京市房山区辰光东路16号院4号楼9层904

模块,光栅系列 您现在的位置:letou国际米兰 > letou国际米兰 > 模块,光栅系列 >

TypeScriptletou国际米兰

发布:admin   浏览:


  请务必注意一点,TypeScript 1.5里术语名已经发生了变化。 “内部模块”现在称做“命名空间”。 “外部模块”现在则简称为“模块”,这是为了与ECMAScript 2015里的术语保持一致,(也就是说

  模块在其自身的作用域里执行,而不是在全局作用域里;这意味着定义在一个模块里的变量,函数,类等等在模块外部是不可见的,除非你明确地使用export形式之一导出它们。 相反,如果想使用其它模块导出的变量,函数,类,接口等的时候,你必须要导入它们,可以使用import形式之一。

  模块是自声明的;两个模块之间的关系是通过在文件级别上使用imports和exports建立的。

  模块使用模块加载器去导入其它的模块。 在运行时,模块加载器的作用是在执行此模块代码前去查找并执行这个模块的所有依赖。 大家最熟知的JavaScript模块加载器是服务于Node.js的CommonJS和服务于Web应用的Require.js。

  TypeScript与ECMAScript 2015一样,任何包含顶级import或者export的文件都被当成一个模块。相反地,如果一个文件不带有顶级的import或者export声明,那么它的内容被视为全局可见的(因此对模块也是可见的)。

  任何声明(比如变量,函数,类,类型别名或接口)都能够通过添加export关键字来导出。

  导出语句很便利,因为我们可能需要对导出的部分重命名,所以上面的例子可以这样改写:

  我们经常会去扩展其它模块,并且只导出那个模块的部分内容。 重新导出功能并不会在当前模块导入那个模块或定义一个新的局部变量。

  或者一个模块可以包裹多个模块,并把他们导出的内容联合在一起通过语法:export * from module。

  模块的导入操作与导出一样简单。 可以使用以下import形式之一来导入其它模块中的导出内容。

  尽管不推荐这么做,一些模块会设置一些全局状态供其它模块使用。 这些模块可能没有任何的导出或用户根本就不关注它的导出。 使用下面的方法来导入这类模块:

  每个模块都可以有一个default导出。 默认导出使用default关键字标记;并且一个模块只能够有一个default导出。 需要使用一种特殊的导入形式来导入default导出。

  default导出十分便利。 比如,像JQuery这样的类库可能有一个默认导出jQuery或$,并且我们基本上也会使用同样的名字jQuery或$导出JQuery。

  类和函数声明可以直接被标记为默认导出。 标记为默认导出的类和函数的名字是可以省略的。

  CommonJS和AMD的环境里都有一个exports变量,这个变量包含了一个模块的所有导出内容。

  export =语法定义一个模块的导出对象。 这里的对象一词指的是类,接口,命名空间,函数或枚举。

  下面的例子说明了导入导出语句里使用的名字是怎么转换为相应的模块加载器代码的。

  编译完成后,每个模块会生成一个单独的.js文件。 好比使用了reference标签,编译器会根据import语句编译相应的文件。

  有时候,你只想在某种条件下才加载某个模块。 在TypeScript里,使用下面的方式来实现它和其它的高级加载场景,我们可以直接调用模块加载器并且可以保证类型完全。

  编译器会检测是否每个模块都会在生成的JavaScript中用到。 如果一个模块标识符只在类型注解部分使用,并且完全没有在表达式中使用时,就不会生成require这个模块的代码。 省略掉没有用到的引用对性能提升是很有益的,并同时提供了选择性加载模块的能力。

  这种模式的核心是import id = require(...)语句可以让我们访问模块导出的类型。 模块加载器会被动态调用(通过require),就像下面if代码块里那样。 它利用了省略引用的优化,所以模块只在被需要时加载。 为了让这个模块工作,一定要注意import定义的标识符只能在表示类型处使用(不能在会转换成JavaScript的地方)。

  为了确保类型安全性,我们可以使用typeof关键字。typeof关键字,当在表示类型的地方使用时,会得出一个类型值,这里就表示模块的类型。

  要想描述非TypeScript编写的类库的类型,我们需要声明类库所暴露出的API。

  我们叫它声明因为它不是“外部程序”的具体实现。 它们通常是在.d.ts文件里定义的。 如果你熟悉C/C++,你可以把它们当做.h文件。 让我们看一些例子。

  在Node.js里大部分工作是通过加载一个或多个模块实现的。 我们可以使用顶级的export声明来为每个模块都定义一个.d.ts文件,但最好还是写在一个大的.d.ts文件里。 我们使用与构造一个外部命名空间相似的方法,但是这里使用module关键字并且把名字用引号括起来,方便之后import。 例如:

  假如你不想在使用一个新模块之前花时间去编写声明,公司动态你可以采用声明的简写形式以便能够快速使用它。

  某些模块加载器如SystemJS和AMD支持导入非JavaScript内容。 它们通常会使用一个前缀或后缀来表示特殊的加载语法。 模块声明通配符可以用来表示这些情况。

  有些模块被设计成兼容多个模块加载器,或者不使用模块加载器(全局变量)。 它们以UMD模块为代表。 这些库可以通过导入的形式或全局变量的形式访问。 例如:

  它同样可以通过全局变量的形式使用,但只能在某个脚本(指不带有模块导入或导出的脚本文件)里。

  用户应该更容易地使用你模块导出的内容。 嵌套层次过多会变得难以处理,因此仔细考虑一下如何组织你的代码。

  从你的模块中导出一个命名空间就是一个增加嵌套的例子。 虽然命名空间有时候有它们的用处,在使用模块的时候它们额外地增加了一层。 这对用户来说是很不便的并且通常是多余的。

  导出类的静态方法也有同样的问题 - 这个类本身就增加了一层嵌套。 除非它能方便表述或便于清晰使用,否则请考虑直接导出一个辅助方法。

  就像“在顶层上导出”帮助减少用户使用的难度,一个默认的导出也能起到这个效果。 如果一个模块就是为了导出特定的内容,那么你应该考虑使用一个默认导出。 这会令模块的导入和使用变得些许简单。 比如:

  对用户来说这是最理想的。他们可以随意命名导入模块的类型(本例为t)并且不需要多余的(.)来找到相关对象。

  你可能经常需要去扩展一个模块的功能。 JS里常用的一个模式是JQuery那样去扩展原对象。 如我们之前提到的,模块不会像全局命名空间对象那样去合并。 推荐的方案是不要去改变原来的对象,而是导出一个新的实体来提供新的功能。

  假设Calculator.ts模块里定义了一个简单的计算器实现。 这个模块同样提供了一个辅助函数来测试计算器的功能,通过传入一系列输入的字符串并在最后给出结果。

  现在扩展它,添加支持输入其它进制(十进制以外),让我们来创建ProgrammerCalculator.ts。

  当初次进入基于模块的开发模式时,可能总会控制不住要将导出包裹在一个命名空间里。 模块具有其自己的作用域,并且只有导出的声明才会在模块外部可见。 记住这点,命名空间在使用模块时几乎没什么价值。

  在组织方面,命名空间对于在全局作用域内对逻辑上相关的对象和类型进行分组是很便利的。 例如,在C#里,你会从System.Collections里找到所有集合的类型。 通过将类型有层次地组织在命名空间里,可以方便用户找到与使用那些类型。 然而,模块本身已经存在于文件系统之中,这是必须的。letou国际米兰, 我们必须通过路径和文件名找到它们,这已经提供了一种逻辑上的组织形式。 我们可以创建/collections/generic/文件夹,把相应模块放在这里面。

  命名空间对解决全局作用域里命名冲突来说是很重要的。 比如,你可以有一个My.Application.Customer.AddForm和My.Application.Order.AddForm-- 两个类型的名字相同,但命名空间不同。 然而,这对于模块来说却不是一个问题。 在一个模块里,没有理由两个对象拥有同一个名字。 从模块的使用角度来说,使用者会挑出他们用来引用模块的名字,所以也没有理由发生重名的情况。

  以下均为模块结构上的危险信号。重新检查以确保你没有在对模块使用命名空间: