TypeScript教程2

在TS中,我们允许开发人员使用面向对象技术。

1、类
让我们看看一个简单的基于类的例子: 

  1. class Greeter {
  2.     greeting: string;
  3.     constructor(message: string) {
  4.         this.greeting = message;
  5.     }
  6.     greet() {
  7.         return "Hello, " + this.greeting;
  8.     }
  9. }
  10. var greeter = new Greeter("world");
复制代码

语法应该非常熟悉,如果你以前使用c#或者Java或者AS。 我们声明一个新的类“Greeter”。 这个类有三个成员,即所谓的“greeting”,构造函数和方法“greet”。 

在类中我们使用greeter.greeting的方式访问类属性。 

在最后一行我们构造一个实例。 这回调用Greeter的constructor方法。
2、继承

在TS中,我们可以使用常见的面向对象模式。 当然,最基本的模式之一,就是扩展现有的类来创建新类。即继承。 

让我们看一个例子: 

  1. class Animal {
  2.     name:string;
  3.     constructor(theName: string) { this.name = theName; }
  4.     move(meters: number) {
  5.         alert(this.name + " moved " + meters + "m.");
  6.     }
  7. }
  8. class Snake extends Animal {
  9.     constructor(name: string) { super(name); }
  10.     move() {
  11.         alert("Slithering...");
  12.         super.move(5);
  13.     }
  14. }
  15. class Horse extends Animal {
  16.     constructor(name: string) { super(name); }
  17.     move() {
  18.         alert("Galloping...");
  19.         super.move(45);
  20.     }
  21. }
  22. var sam = new Snake("Sammy the Python");
  23. var tom: Animal = new Horse("Tommy the Palomino");
  24. sam.move();
  25. tom.move(34);
复制代码

这个例子包括相当多的TS中的继承特性。 在这里,我们看到使用扩展的关键字来创建一个子类。 你可以看到这个“马”和“蛇”子类 类“动物”,获得其功能。 

示例还展示了能够覆盖基类中的方法。 这里“蛇”和“马”创建一个移动的方法,覆盖了从“动物”“移动”。 
3、私人/公共修饰符

您可能已经注意到在上面的例子中我们没有使用“public”这个词使任何成员的类可见。 c#等语言要求每个成员被显式地标记“public”是可见的。 在TS, 每个成员在默认情况下是公共的。 
关于私有变量,我们可以这样写:

  1. class Animal {
  2.     private name:string;
  3.     constructor(theName: string) { this.name = theName; }
  4.     move(meters: number) {
  5.         alert(this.name + " moved " + meters + "m.");
  6.     }
  7. }
复制代码

4、访问器
TS支持getter / setter的拦截访问一个对象的成员。 这可以控制如何访问每个对象成员。 

让我们把一个简单的类,使用“getter ”和“setter”。 首先,让我们从一个示例开始没有getter和setter。 

  1. class Employee {
  2.     fullName: string;
  3. }
  4. var employee = new Employee();
  5. employee.fullName = "Bob Smith";
  6. if (employee.fullName) {
  7.     alert(employee.fullName);
  8. }
复制代码

同时允许人们直接fullName随机设置很方便,如果我们人们可以随意改变名字,可能给我们带来麻烦。 

在这个版本中,我们检查以确保用户有一个秘密的密码可用之前,我们让他们修改员工。 我们通过直接访问fullName替换的“setter”查看密码。 我们添加一个相应的“getter ” 让前面的示例无缝地继续工作。 

  1. var passcode = "secret passcode";
  2. class Employee {
  3.     private _fullName: string;
  4.     get fullName(): string {
  5.         return this._fullName;
  6.     }
  7.         
  8.     set fullName(newName: string) {
  9.         if (passcode && passcode == "secret passcode") {
  10.             this._fullName = newName;
  11.         }
  12.         else {
  13.             alert("Error: Unauthorized update of employee!");
  14.         }
  15.     }
  16. }
  17. var employee = new Employee();
  18. employee.fullName = "Bob Smith";
  19. if (employee.fullName) {
  20.     alert(employee.fullName);
  21. }
复制代码

5、静态属性
到目前为止,我们只讨论了 实例成员,只有当实例化后才可以使用。 我们还可以创建 静态成员,那些不用实例化就可以使用的属性或者方法。 

  1. class Grid {
  2.     static origin = {x: 0, y: 0};
  3.     calculateDistanceFromOrigin(point: {x: number; y: number;}) {
  4.         var xDist = (point.x - Grid.origin.x);
  5.         var yDist = (point.y - Grid.origin.y);
  6.         return Math.sqrt(xDist * xDist + yDist * yDist) / this.scale;
  7.     }
  8.     constructor (public scale: number) { }
  9. }
  10. var grid1 = new Grid(1.0);  // 1x scalevar grid2 = new Grid(5.0);  // 5x scale
  11. alert(grid1.calculateDistanceFromOrigin({x: 10, y: 10}));
  12. alert(grid2.calculateDistanceFromOrigin({x: 10, y: 10}));
复制代码

==================================================

 

 

 

在TS中使用模块通过各种方式组织代码。 我们将要涉及的内部和外部模块。并且讨论如何使用它们。 
1、第一步
我们写一组简单的字符串验证器,像你可能使用时检查用户输入的表单在网页或检查外部提供的格式 数据文件。 
验证器在一个单一的文件中

  1. interface StringValidator {
  2.     isAcceptable(s: string): boolean;
  3. }
  4. var lettersRegexp = /^[A-Za-z]+$/;
  5. var numberRegexp = /^[0-9]+$/;
  6. class LettersOnlyValidator implements StringValidator {
  7.     isAcceptable(s: string) {
  8.         return lettersRegexp.test(s);
  9.     }
  10. }
  11. class ZipCodeValidator implements StringValidator {
  12.     isAcceptable(s: string) {
  13.         return s.length === 5 && numberRegexp.test(s);
  14.     }
  15. }
  16. // Some samples to tryvar strings = ['Hello', '98052', '101'];
  17. // Validators to usevar validators: { [s: string]: StringValidator; } = {};
  18. validators['ZIP code'] = new ZipCodeValidator();
  19. validators['Letters only'] = new LettersOnlyValidator();
  20. // Show whether each string passed each validator
  21. strings.forEach(s => {
  22.     for (var name in validators) {
  23.         console.log('"' + s + '" ' + (validators[name].isAcceptable(s) ? ' matches ' : ' does not match ') + name);
  24.     }
  25. });
复制代码

2、添加模块
当我们添加更多的验证器,我们会想要组织起来,这样我们可以跟踪我们的类型,而不是担心与其他对象名称冲突。让我们将对象放到一个模块中。 
模块化的验证器

  1. module Validation {
  2.     export interface StringValidator {
  3.         isAcceptable(s: string): boolean;
  4.     }
  5.     var lettersRegexp = /^[A-Za-z]+$/;
  6.     var numberRegexp = /^[0-9]+$/;
  7.     export class LettersOnlyValidator implements StringValidator {
  8.         isAcceptable(s: string) {
  9.             return lettersRegexp.test(s);
  10.         }
  11.     }
  12.     export class ZipCodeValidator implements StringValidator {
  13.         isAcceptable(s: string) {
  14.             return s.length === 5 && numberRegexp.test(s);
  15.         }
  16.     }
  17. }
  18. // Some samples to tryvar strings = ['Hello', '98052', '101'];
  19. // Validators to usevar validators: { [s: string]: Validation.StringValidator; } = {};
  20. validators['ZIP code'] = new Validation.ZipCodeValidator();
  21. validators['Letters only'] = new Validation.LettersOnlyValidator();
  22. // Show whether each string passed each validator
  23. strings.forEach(s => {
  24.     for (var name in validators) {
  25.         console.log('"' + s + '" ' + (validators[name].isAcceptable(s) ? ' matches ' : ' does not match ') + name);
  26.     }
  27. });
复制代码

3、跨文件分割【常用】
随着应用程序的增长,我们需要将代码拆分为多个文件,让它更容易维护。 

在这里,我们分开验证模块到多个文件。 即使文件是分开的,他们都能调用相同的模块。 因为有文件之间的依赖关系,我们 添加/// <reference path="Validation.ts" />】引用标记来告诉编译器的文件之间的关系。 否则我们的测试代码不变。 
多文件内部模块Validation.ts

  1. module Validation {
  2.     export interface StringValidator {
  3.         isAcceptable(s: string): boolean;
  4.     }
  5. }
复制代码

LettersOnlyValidator.ts

  1. /// <reference path="Validation.ts" />
  2. module Validation {
  3.     var lettersRegexp = /^[A-Za-z]+$/;
  4.     export class LettersOnlyValidator implements StringValidator {
  5.         isAcceptable(s: string) {
  6.             return lettersRegexp.test(s);
  7.         }
  8.     }
  9. }
复制代码

ZipCodeValidator.ts

  1. /// <reference path="Validation.ts" />
  2. module Validation {
  3.     var numberRegexp = /^[0-9]+$/;
  4.     export class ZipCodeValidator implements StringValidator {
  5.         isAcceptable(s: string) {
  6.             return s.length === 5 && numberRegexp.test(s);
  7.         }
  8.     }
  9. }
复制代码

Test.ts

  1. /// <reference path="Validation.ts" />/// <reference path="LettersOnlyValidator.ts" />/// <reference path="ZipCodeValidator.ts" />
  2. // Some samples to tryvar strings = ['Hello', '98052', '101'];
  3. // Validators to usevar validators: { [s: string]: Validation.StringValidator; } = {};
  4. validators['ZIP code'] = new Validation.ZipCodeValidator();
  5. validators['Letters only'] = new Validation.LettersOnlyValidator();
  6. // Show whether each string passed each validator
  7. strings.forEach(s => {
  8.     for (var name in validators) {
  9.         console.log('"' + s + '" ' + (validators[name].isAcceptable(s) ? ' matches ' : ' does not match ') + name);
  10.     }
  11. });
复制代码

有多个文件后,我们需要确保所有的编译后的代码被加载。 这样做有两种方式。 

首先,我们可以使用连接输出使用 ——编译所有的输入输出文件到一个单独的JavaScript文件: 

  1. tsc --out sample.js Test.ts
复制代码

编译器会自动顺序输出文。 您还可以单独指定每个文件: 

  1. tsc --out sample.js Validation.ts LettersOnlyValidator.ts ZipCodeValidator.ts Test.ts
复制代码

或者,我们可以使用文件编译(默认)为每个输入文件导出到一个JavaScript文件。 如果多个JS文件,我们可以使用 <script> 标签为加载的每个文件排,例如: 
MyTestPage。 html(摘录)

  1.     <script src="Validation.js" type="text/javascript" />
  2.     <script src="LettersOnlyValidator.js" type="text/javascript" />
  3.     <script src="ZipCodeValidator.js" type="text/javascript" />
  4.     <script src="Test.js" type="text/javascript" />
复制代码

4、将外部模块导入【不常用】
TS也有外部模块的概念。 外部模块用于两种情况:node. js和require.js。 应用程序不使用node. js或require.js不需要使用外部模块,最好可以使用内部模块的组织概念 上面概述。 

在编译时,每个外部模块将成为一个单独的. js文件。 类似于参考标签,编译器将遵循imports语句来编译依赖文件。 
Validation.ts

  1. export interface StringValidator {
  2.     isAcceptable(s: string): boolean;
  3. }
复制代码

LettersOnlyValidator.ts

  1. import validation = require('./Validation');
  2. var lettersRegexp = /^[A-Za-z]+$/;
  3. export class LettersOnlyValidator implements validation.StringValidator {
  4.     isAcceptable(s: string) {
  5.         return lettersRegexp.test(s);
  6.     }
  7. }
复制代码

ZipCodeValidator.ts

  1. import validation = require('./Validation');
  2. var numberRegexp = /^[0-9]+$/;
  3. export class ZipCodeValidator implements validation.StringValidator {
  4.     isAcceptable(s: string) {
  5.         return s.length === 5 && numberRegexp.test(s);
  6.     }
  7. }
复制代码

Test.ts

  1. import validation = require('./Validation');
  2. import zip = require('./ZipCodeValidator');
  3. import letters = require('./LettersOnlyValidator');
  4. // Some samples to tryvar strings = ['Hello', '98052', '101'];
  5. // Validators to usevar validators: { [s: string]: validation.StringValidator; } = {};
  6. validators['ZIP code'] = new zip.ZipCodeValidator();
  7. validators['Letters only'] = new letters.LettersOnlyValidator();
  8. // Show whether each string passed each validator
  9. strings.forEach(s => {
  10.     for (var name in validators) {
  11.         console.log('"' + s + '" ' + (validators[name].isAcceptable(s) ? ' matches ' : ' does not match ') + name);
  12.     }
  13. });
复制代码

5、代码生成外部模块
根据模块目标指定在编译,编译器将生成适当的代码为节点。 js(commonjs)或require。 js(AMD)模块加载系统。 更多信息的 define和 require生成的代码,请咨询每个模块的文档加载程序。 

这个简单的例子显示了如何使用的名称在导入和导出翻译成加载模块的代码。 
SimpleModule.ts

  1. import m = require('mod');
  2. export var t = m.something + 1;
复制代码

AMD / RequireJS SimpleModule.js:

  1. define(["require", "exports", 'mod'], function(require, exports, m) {
  2.     exports.t = m.something + 1;
  3. });
复制代码

CommonJS /节点SimpleModule.js:

  1. var m = require('mod');
  2. exports.t = m.something + 1;
复制代码

6、可选模块加载和其他先进加载场景
在某些情况下,您可能希望只在一定条件下加载模块。 在TS中,我们可以使用如下所示的模式来实现这个和其他高级加载场景直接调用模块加载器在不损失类型安全。 
维护类型安全,我们可以使用 typeOf 关键字。 的 typeOf 关键字,当用于输入位置,产生一个值的类型,在本例中外部模块的类型。 
动态加载模块在node . js

  1. declare var require;
  2. import Zip = require('./ZipCodeValidator');
  3. if (needZipValidation) {
  4.     var x: typeof Zip = require('./ZipCodeValidator');
  5.     if (x.isAcceptable('.....')) { /* ... */ }
  6. }
复制代码

在require.js示例:动态加载模块

  1. declare var require;
  2. import Zip = require('./ZipCodeValidator');
  3. if (needZipValidation) {
  4.     require(['./ZipCodeValidator'], (x: typeof Zip) => {
  5.         if (x.isAcceptable('...')) { /* ... */ }
  6.     });
  7. }
复制代码

7、与其他JavaScript库工作
描述的形状库不写typescript,我们需要声明类库公开的API。 因为大多数JavaScript库暴露只有少数顶级对象,模块是一个很好的方式来表示它们。 通常这些都是.d.ts文件中定义。 如果您熟悉C / c++,这些是你能想到的。让我们看看几个例子与内部和外部的例子。 
环境内部模块流行的库D3定义其功能在一个名为“D3”的全局对象。 因为这个库是通过加载script 标签(而不是一个模块加载器),其声明使用内部模块来定义它的形状。TS编译器看到这个形状,我们使用一个环境内部模块声明。 例如: 
D3.d.ts(简化的摘录)

  1. declare module D3 {
  2.     export interface Selectors {
  3.         select: {
  4.             (selector: string): Selection;
  5.             (element: EventTarget): Selection;
  6.         };
  7.     }
  8.     export interface Event {
  9.         x: number;
  10.         y: number;
  11.     }
  12.     export interface Base extends Selectors {
  13.         event: Event;
  14.     }
  15. }
  16. declare var d3: D3.Base;
复制代码

==================================================

 

posted @ 2015-09-23 16:12  凌志华  阅读(336)  评论(0编辑  收藏  举报