【TypeScript】TypeScript 學習 4——模塊

前端數據驗證在改善用戶體驗上有很大做用,在學了以前的知識的時候,咱們極可能會寫出如下代碼:javascript

interface StringValidator {
    isAcceptable(s: string): boolean;
}

var lettersRegexp = /^[A-Za-z]+$/;
var numberRegexp = /^[0-9]+$/;

class LettersOnlyValidator implements StringValidator {
    isAcceptable(s: string) {
        return lettersRegexp.test(s);
    }
}

class ZipCodeValidator implements StringValidator {
    isAcceptable(s: string) {
        return s.length === 5 && numberRegexp.test(s);
    }
}

// Some samples to try
var strings = ['Hello', '98052', '101'];
// Validators to use
var validators: { [s: string]: StringValidator; } = {};
validators['ZIP code'] = new ZipCodeValidator();
validators['Letters only'] = new LettersOnlyValidator();
// Show whether each string passed each validator
strings.forEach(s => {
    for (var name in validators) {
        console.log('"' + s + '" ' + (validators[name].isAcceptable(s) ? ' matches ' : ' does not match ') + name);
    }
});

那麼這段代碼最大的問題是什麼呢?一個是無法複用,驗證的封裝和驗證過程在同一個文件,驗證的封裝已是能夠複用的。另外一個是接口和兩個實現的類都直接掛接在全局變量上,假如數量一多的話,將會污染整個全局變量。前端

模塊化就是爲了解決這一問題而誕生的。java

module Validation {
    export interface StringValidator {
        isAcceptable(s: string): boolean;
    }

    var lettersRegexp = /^[A-Za-z]+$/;
    var numberRegexp = /^[0-9]+$/;

    export class LettersOnlyValidator implements StringValidator {
        isAcceptable(s: string) {
            return lettersRegexp.test(s);
        }
    }

    export class ZipCodeValidator implements StringValidator {
        isAcceptable(s: string) {
            return s.length === 5 && numberRegexp.test(s);
        }
    }
}

// Some samples to try
var strings = ['Hello', '98052', '101'];
// Validators to use
var validators: { [s: string]: Validation.StringValidator; } = {};
validators['ZIP code'] = new Validation.ZipCodeValidator();
validators['Letters only'] = new Validation.LettersOnlyValidator();
// Show whether each string passed each validator
strings.forEach(s => {
    for (var name in validators) {
        console.log('"' + s + '" ' + (validators[name].isAcceptable(s) ? ' matches ' : ' does not match ') + name);
    }
});

咱們使用 module 關鍵字來定義模塊,用 export 關鍵字讓咱們的接口、類等成員對模塊外可見。瀏覽器

這樣,就只有模塊名掛接在全局變量上,最大限度地避免污染全局變量了。異步

  • 分隔模塊到多個文件

隨着咱們項目的擴展,咱們的代碼總不可能只寫在一個文件裏。爲了更好地維護項目,咱們會將特定功能放到一個文件裏,而後加載多個功能實現咱們想須要的功能。如今咱們先將上面的代碼分割到多個文件裏。模塊化

Validation.tsui

module Validation {
    export interface StringValidator {
        isAcceptable(s: string): boolean;
    }
}

LettersOnlyValidator.tsspa

/// <reference path="Validation.ts" />
module Validation {
    var lettersRegexp = /^[A-Za-z]+$/;
    export class LettersOnlyValidator implements StringValidator {
        isAcceptable(s: string) {
            return lettersRegexp.test(s);
        }
    }
}

ZipCodeValidator.tscode

/// <reference path="Validation.ts" />
module Validation {
    var numberRegexp = /^[0-9]+$/;
    export class ZipCodeValidator implements StringValidator {
        isAcceptable(s: string) {
            return s.length === 5 && numberRegexp.test(s);
        }
    }
}

Test.tsblog

/// <reference path="Validation.ts" />
/// <reference path="LettersOnlyValidator.ts" />
/// <reference path="ZipCodeValidator.ts" />

// Some samples to try
var strings = ['Hello', '98052', '101'];
// Validators to use
var validators: { [s: string]: Validation.StringValidator; } = {};
validators['ZIP code'] = new Validation.ZipCodeValidator();
validators['Letters only'] = new Validation.LettersOnlyValidator();
// Show whether each string passed each validator
strings.forEach(s => {
    for (var name in validators) {
        console.log('"' + s + '" ' + (validators[name].isAcceptable(s) ? ' matches ' : ' does not match ') + name);
    }
});

在項目中新建好以上四個文件,而後咱們編譯項目,若是咱們代碼編寫沒錯的話,是可以編譯經過的。另外,咱們能夠見到後面三個文件開頭有相似於 C# 的文檔註釋,這是告訴 TypeScript 編譯器該文件依賴於哪些文件,假如依賴的文件不存在的話,編譯就會不經過。固然咱們不寫也是能夠的,只不過編譯器在編譯時不會幫咱們檢查,通常來講,仍是建議寫上。

另外,在引用編譯生成的 JavaScript 文件時,咱們須要注意好順序。以上面的代碼爲例,咱們在 Html 代碼中已經這麼引用。

<script src="Validation.js" type="text/javascript" />
<script src="LettersOnlyValidator.js" type="text/javascript" />
<script src="ZipCodeValidator.js" type="text/javascript" />
<script src="Test.js" type="text/javascript" />
  • 外部模塊

在上面的方式中,瀏覽器會把 4 個 JavaScript 都加載。但某些時候,咱們並不須要所有都用上,應該實現按需加載。那麼在 TypeScript 中如何實現呢,很簡單,只須要稍微修改一下就行。

Validation.ts

export interface StringValidator {
    isAcceptable(s: string): boolean;
}

LettersOnlyValidator.ts

import validation = require('./Validation');
var lettersRegexp = /^[A-Za-z]+$/;
export class LettersOnlyValidator implements validation.StringValidator {
    isAcceptable(s: string) {
        return lettersRegexp.test(s);
    }
}

ZipCodeValidator.ts

import validation = require('./Validation');
var numberRegexp = /^[0-9]+$/;
export class ZipCodeValidator implements validation.StringValidator {
    isAcceptable(s: string) {
        return s.length === 5 && numberRegexp.test(s);
    }
}

Test.ts

import validation = require('./Validation');
import zip = require('./ZipCodeValidator');
import letters = require('./LettersOnlyValidator');

// Some samples to try
var strings = ['Hello', '98052', '101'];
// Validators to use
var validators: { [s: string]: validation.StringValidator; } = {};
validators['ZIP code'] = new zip.ZipCodeValidator();
validators['Letters only'] = new letters.LettersOnlyValidator();
// Show whether each string passed each validator
strings.forEach(s => {
    for (var name in validators) {
        console.log('"' + s + '" ' + (validators[name].isAcceptable(s) ? ' matches ' : ' does not match ') + name);
    }
});

修改完以後,編譯。。。不經過!

看官們可能以爲我坑爹了,辛辛苦苦敲這麼一大段後,居然編譯不經過。這裏,咱們先說說模塊加載的兩種規範。

CommonJS 規範:

CommonJS 目標在於實現一個相似於 Python、Ruby 等語言的標準庫。而 NodeJS 使用的就是這一規範。

var m = require('mod');
exports.t = m.something + 1;

AMD 規範:

因爲上面的 CommonJS 規範所實現的加載是同步的,但實際上,咱們的瀏覽器更須要的是異步加載,所以 AMD 規範應運而生。

define(["require", "exports", 'mod'], function(require, exports, m) {
    exports.t = m.something + 1;
});

那麼 TypeScript 使用哪一種規範呢?答案是兩種均可以,看須要選擇其中一種。

回到咱們的項目,修改項目屬性。

QQ截圖20150620231137

將這裏修改成 AMD 或者 CommonJS,而後就能夠經過編譯了。

  • Export =

在上面的代碼中,咱們導出模塊的根是文件,所以須要寫成 zip.ZipCodeValidator 這種形式,那爲何不簡化一下呢?直接用 ZipCodeValidator 多好。Export = 就能夠幫助咱們作這件事。

Validation.ts

export interface StringValidator {
    isAcceptable(s: string): boolean;
}

LettersOnlyValidator.ts

import validation = require('./Validation');
var lettersRegexp = /^[A-Za-z]+$/;
class LettersOnlyValidator implements validation.StringValidator {
    isAcceptable(s: string) {
        return lettersRegexp.test(s);
    }
}
export = LettersOnlyValidator;

ZipCodeValidator.ts

import validation = require('./Validation');
var numberRegexp = /^[0-9]+$/;
class ZipCodeValidator implements validation.StringValidator {
    isAcceptable(s: string) {
        return s.length === 5 && numberRegexp.test(s);
    }
}
export = ZipCodeValidator;

Test.ts

import validation = require('./Validation');
import zipValidator = require('./ZipCodeValidator');
import lettersValidator = require('./LettersOnlyValidator');

// Some samples to try
var strings = ['Hello', '98052', '101'];
// Validators to use
var validators: { [s: string]: validation.StringValidator; } = {};
validators['ZIP code'] = new zipValidator();
validators['Letters only'] = new lettersValidator();
// Show whether each string passed each validator
strings.forEach(s => {
    for (var name in validators) {
        console.log('"' + s + '" ' + (validators[name].isAcceptable(s) ? ' matches ' : ' does not match ') + name);
    }
});
  • 別名

module Shapes {
    export module Polygons {
        export class Triangle { }
        export class Square { }
    }
}

import polygons = Shapes.Polygons;
var sq = new polygons.Square(); // Same as 'new Shapes.Polygons.Square()'

這樣寫 import,下面的代碼就能夠簡寫一下。須要注意的是,不支持 require 引入的模塊。

  • declare 關鍵字

有時候咱們須要定義全局變量,那麼咱們就須要增長 declare 關鍵字。

declare ver myString;

那麼 myString 變量就是全局的了。這功能在定義全局模塊時頗有做用。

相關文章
相關標籤/搜索