TypeScript迅速入門與應該知道的基礎
掌握了 TypeScript ,就相當於掌握了 JavaScript 語言的最新標準。前端三大框架中,Angular 2 開始基於 TypeScript 開發,所以最好的學習路線是js->ts->Angular。
TypeScrip優勢
- 支援ES6規範:2015年釋出的,它指出了未來一段時間內,客戶端指令碼語音的發展方向。
- 強大的IDE支援:體現在三個特性上,1.型別檢查,在TS中允許你為變數指定型別。2.語法提示。3.重構。
- Angular2的開發語言
搭建TypeScript開發環境
安裝TypeScript的compiler。compiler(編譯器)的作用是把TS程式碼轉換成JS程式碼;ES6規範是在2015年釋出的,而目前所有主流的瀏覽器並沒有完全支援ES6規範,所以用ES6寫的東西並不能直接放在瀏覽器中去跑。
連結:
安裝:
$ sudo npm install -g typescript
TypeScript的基礎型別
- 布林值 boolean
- 數字 number
- 字串 string
- 陣列 Array
- 元組 Tuple
- 列舉 enum
- 任意值 any
- void
- Null 和 Undefined
- Never
基礎型別示例:
//作用:新增按鈕到body標籤中
let putButton = function (text:string,info:any){
let button = document.createElement("button");
let p = document.createElement("p");
button.textContent = text;
document.body.appendChild(button);
document.body.appendChild(p);
button.onclick = function() {
alert(info);
};
}
//boolean型別
let flag:boolean;
let flag_1:boolean = false;
putButton("let flag:boolean;",flag);
putButton("let flag_1:boolean = false;" ,flag_1);
//number
let PI : number = 3.1415926535897932384626433;//圓周率
putButton("number>>>圓周率PI",PI);
putButton("number>>>圓直徑5,周長",5*PI);
//字串
let str_double_quotes:string = "雙引號宣告string";
let str_single_quote :string = '單引號宣告string';
let str_accent :string = `上點號宣告string`;//可內嵌${表示式}
putButton("string>>>"+str_accent+"${5*8}",`5*8的值:${5*8}`);
//陣列,兩種宣告方式
let nums: number[] = [1, 2, 3,4];
let numList: Array<number> = nums;
putButton("陣列[1,2,3,4]",numList.toString());
//元組Tuple
let dog:[string,number] = ["蝴蝶犬",5];//元組是一個數組,允許元素型別不同
dog[3] = "歲了";//陣列越界不報錯,因為"dog"是string|number聯合型別
// dog[4] = false;//錯誤
putButton("元組Tuple",dog[0]+dog[1]+dog[3]);
//enum 列舉
enum Xiyouji{
唐僧,悟空,八戒=3,沙僧,白龍馬
}//手動指定索引下標
let tangseng:Xiyouji = Xiyouji.唐僧;
let wukong:string = Xiyouji[1];//手動宣告索引,左邊索引從零開始
let shaseng:string = Xiyouji[4];//手動宣告索引,右邊索引依次增加
putButton("enum>>>西遊記",wukong);
//any 任意值
let 水牛:any = "shuiniu";
let shuiniu:number = 100;
水牛 = shuiniu;
putButton("any>>>水牛",水牛);
//void 空值,只能為null或undefined
let v:void = null;
v = undefined;
function f():void{ return v};//空返回值,有點奇怪
putButton("void>>>",f());
//null和undefined,預設情況下null和undefined是所有型別的子型別。其他型別的值一般都可以賦給它們。
let undef: undefined = null;
let nul: null = undefined;
putButton("null和undefined","null和undefined是所有型別的子型別");
//Never型別表示的是那些永不存在的值的型別
//never型別是任何型別的子型別,但沒有型別是never的子型別
// 這意味著never可以賦值給任何型別,但沒有任何型別可以賦值給never型別(除了never本身之外)
let neve:never ;//初值undefined
let go:string = neve;
//never表示永遠不存在值的型別
function trueWhile():never{
while (true){}
}
putButton("never>>>",go);
變數宣告
//此方法在body標籤中追加指定元素和內容
function setElement(elementName:string,contentText:any){
let e = document.createElement(elementName);
e.textContent = contentText;
document.body.appendChild(e);
}
關鍵字
與JavaScript相一致
- var
- const
- let
1.var宣告的變數,可以在包含它的函式,模組,名稱空間或全域性作用域內部任何位置被訪問。也就是說即使是這樣也可以正常執行:
var productName = "Leather wallet";
alert(productName);
2.const 常量,與let具有相同的作用域。 let宣告的變數具有塊級作用域,也就是說被try,if,while等塊包圍時,外部不能訪問。可以有效避免var定義的各種問題。JavaScript本身具備let,IE11支援,參考:
遍歷一個字串陣列,var的宣告:
function forStrVar():void {
let str: string[] = ["極客園地", "BitMan摩肩接踵"];
for (var i = 0; i < str[0].length; i++) {
setElement("p", "------" + str[0].charAt(i) + "------");
//裡面那層第一次迴圈完畢後,i==str[1]的長度-1,覆蓋外層迴圈,導致外層迴圈條件為false,於是外層迴圈只執行一次。
for (var i = 0; i < str[1].length; i++) {
setElement("p", str[1].charAt(i));//contents += str.charAt(i);//var宣告的i互相干架。
}
}
}
改為let聲明後正常。
陣列的解構(重構)
解構陣列,構造陣列。
//陣列的解構
let input = [1, 2];
let [first, second] = input;//相當於使用索引宣告兩個變數first = input[0];second = input[1];
setElement("h1","陣列的解構");
setElement("p",first+"----"+second);
//交換值
[second,first] = [first,second];
setElement("p",first+"----"+second);
//...的形式宣告剩餘變數。
let [o,,u,...t] = [1,2,3,4,5];//一些元素可以不必命名
setElement("p",o+"----"+u+"----"+t);
物件的解構(重構)
類似陣列的解構。JavaScript物件就是json。
let abc = {a: "geek", b: 12, c: "fanr"}//符號:在此處的作用不是宣告型別,而是宣告屬性的值。
let {a,b} = abc;//abc的屬性更多
function中進行解構
type C = { a: string, b?: number };//符號?:表示宣告一個可選的屬性
function f({ a, b }: C): void {//....}
展開陣列
瞭解即可,在宣告中展開一個數組的值構成一個新的陣列:
let num_a = [1,2,3];
let num_b = [...num_a,4,5,"hao"];//使用“...陣列”展開為元組
let num_c = [num_a,4,5,"hao"];//展開
setElement("h1","展開陣列")
setElement("p",num_b);
展開物件
瞭解即可,在宣告中展開一個物件的值構成一個新的陣列:
let dog = {id:1,name:"dog"};
let home = {father:"da",monther:"mo",me:"hao",...dog,name:"狗狗阿里"};//使用"...物件"寫法展開。後宣告的屬性允許覆蓋
setElement("h1","展開物件");
setElement("p",home.name);
介面、類、函式的定義和一些使用形式
要點:需要基本掌握
- 介面允許多繼承
- 類不允許多繼承,但類允許多實現
- 類通過set,get關鍵字宣告存取器
- 介面物件的宣告形式為let shou = <介面>{//…},而不是let shou = new 介面{//…};
關係 | 關鍵字 |
---|---|
Voice | interface |
Animal -> Voice | abstract , class , implement |
Dog -> Animal | class , extend |
Cat -> Animal | class , extend |
Home | class |
ICFMoreH.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>介面、類、函式的定義和一些使用形式</title>
<script src="ICFMore.js"></script>
</head>
<body>
<input type="button" value="千年京巴" onclick="jingbaClick()"/>
<p></p>
<p>
輸入日期:
<input id="month-day" type="text" value=""/>
<button onclick="okClick()">確定</button>
</p>
</body>
</html>
ICFMore.ts
/**
* 介面、類、函式的定義和一些使用形式
*/
//聲音介面
interface Voice {
getLanguage():string;//預設public
speak(content:any):void;
}
abstract class Animal implements Voice{
getLanguage(): string{
return "動物世界通行語";
}
abstract speak(content?: any): void;//可選引數。可選宣告的形式為“修飾符 名稱?:型別”
}
class Dog extends Animal{//private和protected不能出現在模組或名稱空間元素上。此處不允許用來修飾類
// constructor(public name?:string,public id:string,public age:number,public sex:string){//可選引數不允許在固定引數之前
// super();
// }
//此處使用public,為this.xx = xx的簡寫。會自動建立並賦值屬性
constructor(public id:string,public age:number,public sex:string,public name?:string){//不允許多個建構函式實現。。。
super();
}
speak(content: any): void {
alert(content);
}
getLanguage(): string{
return "汪星語";
}
}
class Cat extends Animal{
private _name: string;
speak(content?: any): void {
alert("喵喵!");
}
//getter,setter存取器
set name(name :string){
this._name = name;
}
get name():string{
return this._name;
}
}
class Home{
// let dogB:Dog = new Dog("001",4,"雌","go");//不能在此使用let,var宣告
private catA:Cat = new Cat();
private dogA:Dog = new Dog("001",4,"雌","go");
private readonly tag?:string = "山頂洞人的home";//可選的、只讀屬性的home。可選宣告的形式為“修飾符 名稱?:型別”
protected go(){
}
play(monthDay:any){//預設public
this.catA.name="我是一隻喵";//需要使用this.屬性來訪問,直接訪問不到
this.dogA.name = "我是一隻汪";
console.log(monthDay);
monthDay = parseInt(monthDay,10);//字串轉成十進位制數字
let select = monthDay % 2;
switch (select){
case 0:
alert("Today,我 play with "+this.dogA.name);
break;
case 1:
alert("Today,我 play with "+this.catA.name);
break;
default:
alert("未知日期,我 play with "+this.dogA.name);
break;
}
}
}
//北京哈巴
function jingbaClick(){
let jingba:Dog = new Dog("京巴001",4,"雌");
jingba.speak("汪汪!");
}
function okClick(){
let home: Home = new Home();
let day = (<HTMLInputElement> document.getElementById("month-day")).value;//HTMLElement中沒有value屬性。需要型別斷言(強轉)
// let day = (document.getElementById("month-day") as HTMLInputElement).value;//;型別斷言的另一種方式。
home.play(day);
}
迭代器
- for
- while
for…of 和 for…in:
- for…in 迭代物件的 鍵 的列表
- for…of 迭代物件的 鍵 對應的值
具體區別:
let list = [4, 5, 6];
for (let i in list) {
console.log(i); // "0", "1", "2",索引
}
for (let i of list) {
console.log(i); // "4", "5", "6",值
}
//普通寫法
for (let i = 0; i < list.length; i++) {
let num = list[i];
console.log(num);// "4", "5", "6",值
}
1.do…while和while
- while 直接迴圈{}中程式碼
- do…while 先執行了do塊的程式碼
具體區別:
let list = [1,2,3,4,5];
//箭頭函式表示式。能夠在函式建立時繫結this,避免一些問題。常規寫法則是咋函式呼叫時繫結,這時的this可能並非預期。
let wheel_do = ()=>{
let i =0;
do {
// console.log(list[i]);
htmlLog(list[i]);
i++;//先執行了do塊的程式碼
}while (i<list.length);
};
let wheel = () => { //簡單來說就是解決this指向不明的問題。
let i = 0;
while (i < list.length) {
htmlLog(list[i]);
i++;
}
}
let htmlLog = function (text:any) {
let e = document.createElement("p");
e.textContent = text;
document.body.appendChild(e);
}
// wheel_do();
wheel();
箭頭函式
ts中函式像其他值一樣可以當成引數傳來傳去。箭頭函式可用來定義匿名函式:
對陣列中所有元素進行求和操作
var result = [1, 2, 3]
.reduce((total, current) => total + current, 0);
console.log(result);
this關鍵字:
代替TypeScript裡預設的原型方法,你可以使用一個例項箭頭函式來定義類成員:
class MyClass {
private status = "blah";
public run = () => { // <-- note syntax here
alert(this.status);
}
}
var x = new MyClass();
$(document).ready(x.run); // SAFE, 'run' will always have correct 'this'
模組的匯入與匯出
常用,需要掌握
關鍵字:
- import
- export
匯入與匯出涉及模組,需要有載入器才能執行起來。比如服務於Node.js的CommonJS和服務於Web應用的Require.js。
模組:
- ECMAScript 2015引入。TypeScript沿用。
- 自身有作用域。需要通過匯入、匯出才能夠引入與使用其他模組中的內容。
- TypeScript與ECMAScript 2015中,任何包含頂級 import 或者 export
的檔案(.ts檔案,而不是一個類或介面) 都被當成一個模組。
匯出的方式
1. 宣告時直接匯出
export let goHome :string = "go home";
export interface Hot{
//...
}
2. 使用export{}語句匯出
interface Hot{
//...
}
export{Hot};
//export{Hot as HotDog};//Hot作為HotDog匯出,重新命名。as在型別斷言也有相似用法。
- 重新匯出
用於匯出另一個模組的部分內容,或將多個模組一起匯出。
匯出一個模組的部分內容:
HotHome.ts
export let dog = "熱狗";
export interface Hot{
eat();
}
DogHome.ts
export class Dog{
eat(){
alert("eat ");
}
}
export {dog as nimaDog} from “./HotHome”;//從HotHome模組中匯出dog,重新命名為尼瑪dog
匯出之後使用import使用它:
TestHotDog.ts
import {nimaDog as nimashou} from "./DogHome";//從DogHome模組中匯入nimadog,重新命名為尼瑪獸
class Test{
go(){
alert(nimashou);
}
}
多個模組一起匯出:
語法:export * from "module"
示例:
export * from "./HotHome";
export * from "./DogHome";
4.預設匯出
- 一個模組僅可以有一個預設匯出。其宣告形式為:export default xxx。
- 類和函式的使用預設匯出後,在匯入時可以省略名字。
使用預設匯出:
JQuery.d.ts
declare let $: JQuery;
export default $;
匯入:
App.ts
import $ from "JQuery";
$("button.continue").html( "Next Step..." );
匯入的方式
匯入的方式和匯出類似
1.直接匯入宣告
import {Coffee} from "./CoffeeHome"; //從CoffeeHome模組匯入export宣告的Coffee介面
2.匯入宣告並重命名
import {cat as Persiancat} from "./CoffeeHome";` //從CoffeeHome模組匯入export宣告的cat,重新命名為Persian cat
3.所有export宣告全部匯入
import * as temp from "./CoffeHome";//從CoffeHome模組匯入所有的export宣告,命名為,使用時通過x呼叫。
let catty = temp.Persiancat;
4.具有副作用的匯入
官方文件這麼描述:
儘管不推薦這麼做,一些模組會設定一些全域性狀態供其它模組使用。 這些模組可能 沒有任何的匯出或使用者根本就不關注它的匯出。 使用下面的方法來匯入這類模組:
import "./my-module.js";
匯入與匯出綜合示例:
使用export關鍵字匯出寫好的模組:
Email.ts
export class Email {
public static dress:string;
public static content:string;
sendTo(dress:string,content:string){
console.log("/n寄往:"+dress + "/n內容:"+content);
Email.dress = dress;
Email.content = content;
}
received(){
console.log("/n收到:"+Email.dress+"/n內容:"+Email.content);
return {d:Email.dress,c:Email.content};
}
}
使用import關鍵字匯入Email模組,並使用它:
Biaoju.ts
import { Email } from "./Email";
/**
* 鏢局
*/
export class Biaoju {
/**
* 押鏢:貨物
* 押鏢時要發郵件通知委託人
*/
yabiao(huowu:string){
let email :Email = new Email();
email.sendTo("北京","我們今天開始押鏢。"+Date.now());
console.log("押鏢:"+huowu);
}
}
Jiefei.ts
import {Email as Feigechuanshu} from "./Email";//匯入Email模組,重新命名為飛鴿傳書
/**
* 劫匪
*/
export class Jiefei{
/**
* 收到郵件之後,開始打劫
*/
dajie(){
let feige:Feigechuanshu = new Feigechuanshu();
let xin:{d:string,c:string} = feige.received();//收到信
console.log("收到飛鴿傳書,來自:"+xin.d+"內容:"+xin.c);
alert(`${shanzhai},呔,留下買路財!`);
}
}
export let shanzhai = "劫機山寨";
繼續引入模組,將劫匪和鏢局模組引入:
testGo.ts
import {Biaoju} from "./Biaoju";
import {Jiefei} from "./Jiefei";
let biaoju_A = new Biaoju();
let jiefei_shanzaiA = new Jiefei();
biaoju_A.yabiao("百年大蘿蔔");
jiefei_shanzaiA.dajie();
使用module宣告模組
TypeScript使用module宣告模組,就能夠直接跑了。
Geek.ts
module Geek{
export class Geek{
speak(){
alert("I'm a Geek. You're a Geek. Let's Geek out.");
}
}
}
呼叫模組:
TestGeek.ts
let geekfanr = new Geek.Geek();
geekfanr.speak();
使用時,要引入所有編譯的JavaScript檔案:
TestGeekH.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>極客</title>
</head>
<body>
<script src="Tugeek.js"></script>
<script src="TestGeek.js"></script>
</body>
</html>
執行,彈出一個“I’m a Geek. You’re a Geek. Let’s Geek out.”對話方塊。