前言
typescript(以下簡(jiǎn)稱ts)是微軟開發(fā)、google(Angular2)支持的 js超集(增加面向?qū)ο缶幊痰奶匦院湍承〦S6語法特性)渐裸,任何js都可以不經(jīng)修改的在ts環(huán)境下運(yùn)行。很多著名的項(xiàng)目都已經(jīng)將ts作為了開發(fā)語言装悲,例如昏鹃,我國(guó)的HTML5游戲引擎Egret、我國(guó)的前端樣式庫Ant-desgin等诀诊《床常總之,ts絕對(duì)代表了未來的大前端語言趨勢(shì)属瓣,不學(xué)就落后了载迄。
ts環(huán)境開發(fā)
一般情況下讯柔,可以在babel或者ts的在線練習(xí)環(huán)境來快速體驗(yàn)ts語言。但是护昧,為了做項(xiàng)目魂迄,還是需要在本地安裝好開發(fā)環(huán)境的,接下來捏卓,我們就看看如何在本地配置開發(fā)環(huán)境和IDE的极祸。
安裝compiler
npm i -g typescript
tsc --version
// 新建一個(gè)test.ts文件
export class testTS {
}
tsc test.ts --->編譯--->test.js
"use strict";
exports.__esModule = true;
var testTS = /** @class */ (function () {
function testTS() {
}
return testTS;
}());
exports.testTS = testTS;
與vscode進(jìn)行集成
tsc --init // 創(chuàng)建tsconfig.json
有了tsconfig.json文件后,就可以對(duì)文件進(jìn)行配置怠晴,設(shè)置好js文件夾和ts文件夾。
編譯ts文件
使用vscode編譯ts文件非常的方便浴捆,只需要run task即可蒜田。
run task后會(huì)出現(xiàn)tsc:build 、tsc:watch兩個(gè)選項(xiàng)选泻,tsc:build是快速編譯冲粤,tsc:watch是實(shí)時(shí)、監(jiān)控編譯页眯,編譯好后梯捕,文件就會(huì)存在于在tsconfig.json指定好的目錄下了。
前端工程比較龐大的時(shí)候窝撵,或者需要將多個(gè)ts輸出到多個(gè)js文件夾下的時(shí)候傀顾,建議使用webpack、gulp或者grunt來進(jìn)行項(xiàng)目的打包和編譯碌奉。這幾個(gè)工具都是前端工程化的工具短曾,在此不做一一展開來講了。
簡(jiǎn)單學(xué)學(xué)ts語法
ts語法很多也是es6語法赐劣,因此嫉拐,簡(jiǎn)單說說一些ts語法,全當(dāng)對(duì)es6進(jìn)行復(fù)習(xí)了魁兼。
字符串特性
多行字符串
使用``
字符串模板
使用`${xxx}`
自動(dòng)拆分字符串
下圖婉徘,test函數(shù)可以通過字符串模板來調(diào)用參數(shù),就是后邊的這些咐汞,可以用字符串模板調(diào)用盖呼,然后,自動(dòng)拆分
參數(shù)
指定參數(shù)類型
使用【冒號(hào) = :】來指定變量碉考、參數(shù)塌计、函數(shù)返回值類型,并且侯谁,類型具有推斷機(jī)制锌仅,如果給string類型的變量章钾,賦值數(shù)字的話,IDE會(huì)報(bào)錯(cuò)热芹。(這里也僅僅是IDE會(huì)報(bào)錯(cuò)贱傀,因此,js是動(dòng)態(tài)語言伊脓,不存在類型的概念府寒,通過ts轉(zhuǎn)換為js不管怎么說都是對(duì)的)
另外,通過類的概念自定類型后报腔,自定義的類型也可以作為普通類型使用
var nymm:string='11111dssasd'
var nymm:any='11111dssasd'
var nymm:number='11111dssasd'
var nymm:boolean='11111dssasd'
// 可選參數(shù)株搔,b就是可選參數(shù),可以不傳遞
function test(er:string,ki:string = "ddd",op?:string):void{
}
// 自定義類型
class Car {
name:string;
logo:string
}
var ben:Car = new Car();
默認(rèn)參數(shù)與可選參數(shù)
給參數(shù)賦默認(rèn)值纯蛾,如果有普通參數(shù)纤房,那么,默認(rèn)參數(shù)不可以為第一個(gè)參數(shù)翻诉,否則炮姨,在賦值的時(shí)候,會(huì)對(duì)參數(shù)的賦值進(jìn)行覆蓋碰煌。同時(shí)舒岸,還提供了【問號(hào) = ?】來指定其為可選參數(shù)芦圾,并且蛾派,可選參數(shù)必須放在必選參數(shù)之后。
function test(er:string,ki:string = "ddd",op?:string):void{
}
函數(shù)
Rest and Spread操作符
Rest and Spread操作符堕扶,例如【...args】碍脏,這個(gè)操作符表示可以聲明任意數(shù)量的方法參數(shù)。這個(gè)參數(shù)表示的是一個(gè)數(shù)組稍算,調(diào)用該參數(shù)的時(shí)候典尾,要按照數(shù)字的方式進(jìn)行處理。
// 任意長(zhǎng)度參數(shù)定義
function fun(...args){}
// 定長(zhǎng)參數(shù)定義
function fun2(a,b,c)
var ays = [1,2,9]
// 定長(zhǎng)函數(shù)調(diào)用
fun2(...ays)
generator和async函數(shù)操縱順序程序
generator以及async函數(shù)糊探,都是promise的語法糖钾埂。用來控制函數(shù)的執(zhí)行過程,通過yield和await來控制代碼的執(zhí)行科平。配合著next()褥紫,來控制順序程序的暫停和開啟。然后瞪慧,每次髓考,調(diào)用next(),都會(huì)停在某一個(gè)yield或者async弃酌。
對(duì)于異步函數(shù)氨菇,其實(shí)就是promise的返回儡炼,因此,直接操作返回的對(duì)象即可查蓉。
析構(gòu)表達(dá)式(destructuring)
通過表達(dá)式將對(duì)象或數(shù)組拆解成任意數(shù)量的變量
拆解對(duì)象
拆解數(shù)組
箭頭表達(dá)式
用來聲明匿名函數(shù)乌询,消除傳統(tǒng)匿名函數(shù)的this指針問題,因?yàn)橥阊校琷s中的this關(guān)鍵字妹田,會(huì)發(fā)生js指向和預(yù)期指向不一致的情況。因?yàn)榫楣玻瑃his的指向是調(diào)用自己的函數(shù)的指向鬼佣,但是,因?yàn)殚]包霜浴、函數(shù)嵌套調(diào)用等原因沮趣,this的指向會(huì)發(fā)生改變。通過箭頭表達(dá)式坷随,將this指向了最外層的函數(shù),從而驻龟,讓一個(gè)函數(shù)內(nèi)共享了this內(nèi)存温眉,從而解決指向改變的問題。
最簡(jiǎn)單的匿名函數(shù)
var kill = (bill,kate)=>bill + kate;
等價(jià)于
var kill = function (bill,kate) {return bill + kate};
例如翁狐,上圖的情況类溢,this指向了匿名函數(shù),因此會(huì)打印不出值露懒。
對(duì)于非箭頭函數(shù)表達(dá)式下的this的簡(jiǎn)單說明
在普通函數(shù)中闯冷,this指代的是調(diào)用他的函數(shù),例如
var obj = {
foo: function () { console.log(this.bar) },
bar: 1
};
var foo = obj.foo;
var bar = 2;
obj.foo() // 1
foo() // 2
這個(gè)函數(shù)打印的就不是一個(gè)值懈词,因?yàn)樯咭琭oo是引用,因此是全局環(huán)境下的對(duì)象對(duì)于this的調(diào)用坎弯,因此纺涤,值是不一樣的。
當(dāng)然抠忘,關(guān)于this撩炊,很有必要單獨(dú)開一個(gè)文章來講解
循環(huán)
本節(jié)將要講解forEach()、for in崎脉、for of循環(huán)的異同
forEach()
forEach()拧咳,有兩個(gè)特性,第一是不能break跳出囚灼,第二是會(huì)忽略對(duì)象的展示骆膝。
for in
for in循環(huán)的是keys祭衩,同時(shí)可以使用break跳出。
for of
for of循環(huán)的是values谭网,同時(shí)可以使用break跳出汪厨。
面向?qū)ο?/h1>
ts的面向?qū)ο螅蛘哒fjs的面向?qū)ο笈cc++或者java很不一樣愉择。因?yàn)檫@種解釋型的語言劫乱,本身就已經(jīng)是對(duì)象了,因此锥涕,在操縱內(nèi)存的時(shí)候要格外小心衷戈。
Class
ts要求使用面向?qū)ο蟮奶匦詠頃鴮懗绦颍热皇敲嫦驅(qū)ο蟛阕梗敲粗掣荆涂梢愿玫睦美^承、封裝和多態(tài)了破花。使用面向?qū)ο笄ぃ梢愿玫膶?shí)現(xiàn)抽象定義和整個(gè)程序的架構(gòu)。
定義
我們可以看到es5下座每,類的定義是基于匿名函數(shù)和閉包的前鹅,同時(shí)還提供了prototype這個(gè)屬性。在此不做展開峭梳,大家自行查閱資料舰绘。(此處涉及到匿名函數(shù)的調(diào)用和原型鏈的知識(shí),此處建議學(xué)習(xí)v8引擎的相關(guān)說明資料https://v8.dev/docs和ECMAScript的說明文檔https://tc39.es/ecma262/#sec-ecmascript-specification-types)
另外葱椭,對(duì)于上邊的代碼捂寿,特別要注意的是,在es5下孵运,匿名函數(shù)一定要自執(zhí)行后秦陋,才能調(diào)用,因?yàn)槠桑跊]有執(zhí)行前踱侣,匿名函數(shù)沒有意義。
訪問控制符
默認(rèn)的訪問控制符是public大磺,同時(shí)還可以添加private和protected抡句。public表示都可以訪問,private表示內(nèi)部訪問杠愧,protected表示內(nèi)部包或者子類可以訪問待榔。
構(gòu)造函數(shù)(constructor())
構(gòu)造函數(shù)的參數(shù),一定要顯式的做訪問控制符的聲明,否則需要在外部單獨(dú)指定其訪問控制權(quán)限锐锣。
繼承(extends和super)
如果我們用es5來實(shí)現(xiàn)class和extends語法糖的話腌闯,那么就應(yīng)該是這樣的幾個(gè)函數(shù),此處又涉及到多個(gè)問題雕憔,因此姿骏,之后會(huì)專門開個(gè)文章系列來討論這部分內(nèi)容。另外斤彼,通過查看es5的實(shí)現(xiàn)方式分瘦,我們也明白了,extends和super的意義琉苇。
var __extends = (this && this.__extends) || (function () {
var extendStatics = function (d, b) {
extendStatics = Object.setPrototypeOf ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
return extendStatics(d, b);
}
return function (d, b) {
extendStatics(d, b);
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
})();
var Animal = /** @class */ (function () {
function Animal(name) {
this.name = name;
}
Animal.prototype.move = function (distanceInMeters) {
if (distanceInMeters === void 0) { distanceInMeters = 0; }
console.log(this.name + " moved " + distanceInMeters + "m.");
};
return Animal;
}());
var Snake = /** @class */ (function (_super) {
__extends(Snake, _super);
function Snake(name) {
return _super.call(this, name) || this;
}
Snake.prototype.move = function (distanceInMeters) {
if (distanceInMeters === void 0) { distanceInMeters = 5; }
console.log("Slithering...");
_super.prototype.move.call(this, distanceInMeters);
};
return Snake;
}(Animal));
var Horse = /** @class */ (function (_super) {
__extends(Horse, _super);
function Horse(name) {
return _super.call(this, name) || this;
}
Horse.prototype.move = function (distanceInMeters) {
if (distanceInMeters === void 0) { distanceInMeters = 45; }
console.log("Galloping...");
_super.prototype.move.call(this, distanceInMeters);
};
return Horse;
}(Animal));
var sam = new Snake("Sammy the Python");
var tom = new Horse("Tommy the Palomino");
sam.move();
tom.move(34);
泛型(generic)
參數(shù)化的類型嘲玫,一般用來限制集合的內(nèi)容。換句話說并扇,就是聲明某個(gè)集合必須是什么數(shù)據(jù)類型去团。
var workers:Array<Worker> = []
這個(gè)數(shù)組就要求,我們只能將worker放到數(shù)組中穷蛹。
接口(interface)
用來建立某種代碼約定土陪,使得其他開發(fā)者在調(diào)用某個(gè)方法或者創(chuàng)建新的類時(shí)必須遵循接口所定義的代碼約定。使用interface定義肴熏,使用implements引用旺坠。
定義接口并使用
基于implements實(shí)現(xiàn)接口
模塊(Module)
在ts或者js中,一個(gè)文件扮超,其實(shí)就是一個(gè)模塊,通過export和import進(jìn)行模塊的導(dǎo)出和導(dǎo)入蹋肮。
模塊可以幫助開發(fā)者將代碼分割為可重用的單元出刷。開發(fā)者可以自己決定將模塊中的哪些資源(類、方法坯辩、變量)暴露出去供外部使用馁龟,哪些資源只在模塊內(nèi)部使用。
值得注意的是漆魔,對(duì)于繼承來說坷檩,因?yàn)椋惪隙ㄒ彩窃诓煌K中的改抡,因此矢炼,我們既要將模塊import,還要extends對(duì)應(yīng)的類阿纤。(此處要注意CommonJS(CMD句灌、AMD)和es6模塊的異同)
注解(annotation)
注解為程序的元素(類、方法、變量)加上更加直觀的說明胰锌,這些說明信息與程序的業(yè)務(wù)邏輯無關(guān)骗绕,只是供指定的工具或者框架使用。(關(guān)于注解资昧,可以具體查看相關(guān)工具的文檔)
類型定義文件(*.d.ts)
ts想要使用js工具包已有的程序應(yīng)該怎么辦呢酬土?之前以及說過了,js可以不經(jīng)修改的在ts下執(zhí)行格带,那么撤缴,我們其實(shí)可以直接調(diào)用js,但是践惑,又存在語法差異腹泌,不免會(huì)產(chǎn)生bug,因此尔觉,使用類型定義文件來幫助ts調(diào)用js的已有代碼凉袱,放在bug的產(chǎn)生。例如:koa等
類型定義文件侦铜,來源于DefinitelyTyped項(xiàng)目https://github.com/DefinitelyTyped/DefinitelyTyped
例如koa的類型定義文件就是在這個(gè)下邊https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/koa/index.d.ts专甩,通過 npm i @types/koa便可以安裝這個(gè)項(xiàng)目,也可以通過typings來安裝和查找钉稍。這個(gè)項(xiàng)目中涤躲,有大量的已有js項(xiàng)目的類型定義文件。
注意贡未,其實(shí)還可以通過通過typings(https://github.com/typings/typings)來尋找以及存在的類型定義文件种樱。但是,由于官方推薦 NPM @types的形式來安裝類型定義文件俊卤,因此嫩挤,可以不去安裝typings了,直接使用npm的安裝方式即可消恍。
npm WARN deprecated typings@2.1.1: Typings is deprecated in favor of NPM @types -- see README for more information
npm WARN deprecated popsicle-proxy-agent@3.0.0: Use `agent` option with `popsicle` directly
npm i typings -g
typings search --name project_name
typings install project_name --save
后記
本文概要的講解了ts和ts的面向?qū)ο笃裾眩瑢?duì)于很多知識(shí)都沒有展開來講,例如狠怨,es5為什么要那樣構(gòu)建類约啊,class、extends等語法糖的es5版本為啥要那樣寫佣赖,注解如何使用等等恰矩。
對(duì)于此部分的內(nèi)容,我將會(huì)在后續(xù)的專題中憎蛤,深入討論的枢里。
討論一下ts做后端開發(fā)
對(duì)于使用過Java、PHP、C#等開發(fā)后端的程序員來說栏豺,ts語法會(huì)讓你們感到更加的親切彬碱。但是,因?yàn)榘峦荩瑃s本身還在發(fā)展巷疼,因此,例如裝飾器灵奖、注解等還是需要第三方庫進(jìn)行支持嚼沿。
Routing-controllers庫
https://github.com/typestack/routing-controllers
該庫為express、koa添加了裝飾器模式瓷患,可以通過注解的方式來操控web服務(wù)器骡尽。
TypeDI依賴注入庫
https://github.com/pleerock/typedi