慕課網(wǎng)@JoJozhai 老師 TypeScript入門(mén)課程分享
<a >TypeScript入門(mén)</a>
ES5,ES6,JS,TypeScript間的關(guān)系
ES5、ES6是兩個(gè)版本的語(yǔ)言規(guī)則倡怎,他們規(guī)定了腳本語(yǔ)言如何去寫(xiě)穴肘,瀏覽器對(duì)應(yīng)的去解析而JS腳本語(yǔ)言應(yīng)用的就是ES5規(guī)則陪踩,TypeScript(以下簡(jiǎn)稱ts)應(yīng)用的是ES6規(guī)則掉奄,且由微軟公司開(kāi)發(fā)
?在我個(gè)人理解,TypeScript是用更豐富的語(yǔ)法簡(jiǎn)便或優(yōu)化了JavaScript里一些比較復(fù)雜贷洲、非人性化的代碼編寫(xiě)過(guò)程盏筐,就如less围俘、sass之于css
?值得一提的是:新版本的angular2是由谷歌團(tuán)隊(duì)開(kāi)發(fā),基礎(chǔ)代碼應(yīng)用TypeScript編輯的前端框架,因此可認(rèn)為是由兩大科技巨頭主導(dǎo)的技術(shù)
TypeScript環(huán)境搭建
-
為何要搭建環(huán)境
目前的主流瀏覽器對(duì)TypeScript的支持還不夠完善界牡,因此需要編譯工具將TypeScript代碼轉(zhuǎn)譯成主流的JS代碼才能得以使用
-
本地安裝TypeScript環(huán)境compiler
在NodeJs條件下命令行輸入以下代碼全局安裝TypeScript環(huán)境
npm install -g typescript
?安裝完成后輸入
tsc -v
?查看TypeScriptCompiler版本
-
tsc使用
進(jìn)入到TypeScript文件所在的目錄簿寂,在此目錄的命令行中運(yùn)行tsc命令將.ts文件轉(zhuǎn)譯為.js文件
tsc index.ts
(轉(zhuǎn)譯index.ts文件)
?會(huì)在相同目錄下生成一個(gè)index.js文件
-
IDE自動(dòng)編譯
上面的方法在實(shí)際開(kāi)發(fā)過(guò)程中顯得十分的笨拙,而主流的IDE都為ts文件準(zhǔn)備了一套自動(dòng)tsc的方法欢揖,例如在webstorm中陶耍,開(kāi)啟設(shè)置項(xiàng)languages中的TypeScript勾選Enable TypeScript compiler選項(xiàng),即可自動(dòng)在ts文件下生成對(duì)應(yīng)的js文件
TypeScript語(yǔ)法
-
字符串
-
聲明多行字符串
?ts中允許聲明字符串中換行,如下
var str = '123
456
789';
轉(zhuǎn)譯后在js文件中代碼會(huì)自動(dòng)添加換行符她混,如下
var str = '123\n456\n789';
-
字符串模板
?ts中可以用`符號(hào)(大鍵盤(pán)1左邊)對(duì)字符串模板進(jìn)行引用烈钞,如下
var myName = 'programmer';
var getName = function () {return 'programmer'};
console.log(`I am ${myName}`); //此處小括號(hào)中不是引號(hào)
console.log(`I am ${getName()}`);
轉(zhuǎn)譯js代碼如下
var myName = 'programmer';
var getName = function () {
return 'programmer';
};
console.log("I am " + myName);
console.log("I am " + getName());
-
自動(dòng)拆分字符串
當(dāng)將字符串模板應(yīng)用到某一函數(shù)中時(shí),將根據(jù)某種規(guī)則將模板進(jìn)行拆分坤按,拆分成函數(shù)相應(yīng)個(gè)數(shù)的參數(shù)并調(diào)用毯欣,例如
function test(template,name,age) {
console.log(template);
console.log(name);
console.log(age)
}
var myname = 'programmer';
var getAge = function () {
return 18;
}
test`hello my name is ${myname}, I am ${getAge() }`
在其轉(zhuǎn)譯并運(yùn)行后,我們會(huì)發(fā)現(xiàn)模板被拆分為三個(gè)參數(shù)打印出來(lái)
對(duì)應(yīng)temlpate參數(shù)的是一個(gè)數(shù)組
Array[3]
0:"hello my name is "
1:", I am "
2:""
對(duì)應(yīng)name參數(shù)的是"programmer",對(duì)應(yīng)age參數(shù)的是 18
也就相當(dāng)于模板被兩段${}分割的每個(gè)部分構(gòu)成了第一個(gè)參數(shù)臭脓,而兩個(gè)${}是另外兩個(gè)參數(shù)
-
參數(shù)酗钞、變量新特性
-
變量類型聲明
ts中聲明變量時(shí)可用冒號(hào):
對(duì)其類型進(jìn)行聲明,或ts文件會(huì)對(duì)其自動(dòng)聲明来累。聲明過(guò)類型的變量用其他類型的值進(jìn)行賦值時(shí)會(huì)引發(fā)ts報(bào)錯(cuò)(注意:在被轉(zhuǎn)譯為js后并不會(huì)引發(fā)任何報(bào)錯(cuò))砚作,如下圖(波浪線即為報(bào)錯(cuò)),而:any
則代表聲明為任意類型嘹锁,可像js中隨意賦值
-
函數(shù)參數(shù)類型定義
同樣對(duì)函數(shù)參數(shù)的聲明此方法也成立葫录,另外可以在函數(shù)聲明時(shí)對(duì)其是否返回值進(jìn)行聲明,:void
表示無(wú)返回值
聲明類屬性類型
在聲明類和對(duì)已聲明類進(jìn)行調(diào)用時(shí)也可使用此規(guī)則领猾,如
class Programmer {
skill: string;
age: number;
}
var me: Programmer = new Programmer();
me.age = 18;
me.skill = 'ts';
-
聲明函數(shù)參數(shù)默認(rèn)值
在聲明函數(shù)時(shí)米同,可以用=
對(duì)參數(shù)聲明默認(rèn)值,這樣在調(diào)用時(shí)若缺失此參數(shù)也不會(huì)報(bào)錯(cuò)摔竿,而是會(huì)按默認(rèn)值進(jìn)行調(diào)用(注意:帶有默認(rèn)值的參數(shù)一定要放在后面聲明面粮,否則將報(bào)錯(cuò))
function test(a:string,b:string,c:string = 'ccc'){
console.log(a);
console.log(b);
console.log(c);
}
test('aaa','bbb');
//打印aaa,bbb,ccc
-
聲明可選參數(shù)
在聲明函數(shù)時(shí),可以在參數(shù)后用?
表示此參數(shù)可選(注意:可選參數(shù)一定要放在必選參數(shù)之后继低,否則將報(bào)錯(cuò))
function test(a:string,b?:string,c:string = 'ccc'){
console.log(a);
console.log(b);
console.log(c);
}
test('aaa');
//打印aaa,undefined,ccc
-
函數(shù)新特性
-
rest and spread操作符
ts可以在聲明函數(shù)時(shí)用...args
聲明不定數(shù)量個(gè)參數(shù)
function test(...args) {
args.forEach(function (arg) {
console.log(arg)
})
};
test(1, 2, 3, 4);
//打印1,2,3,4
轉(zhuǎn)譯為js后如下
function test() {
var args = [];
for (var _i = 0; _i < arguments.length; _i++) {
args[_i] = arguments[_i];
}
args.forEach(function (arg) {
console.log(arg);
});
}
;
test(1, 2, 3, 4);
也可以對(duì)聲明了固定數(shù)量參數(shù)的函數(shù)進(jìn)行參數(shù)數(shù)量不等的調(diào)用
function test(a,b,c) {
console.log(a);
console.log(b);
console.log(c);
};
var arr = [1, 2];
test(...arr);//打印1,2,undefined
var arr2 = [1, 2, 3, 4, 5, 6];
test(...arr2);//只識(shí)別前三個(gè)參數(shù),打印1,2,3
-
generator函數(shù)
通過(guò)function*
聲明一個(gè)generator函數(shù)在函數(shù)中添加yield
和next()
可對(duì)其進(jìn)行打斷和分布執(zhí)行操作熬苍,如下
function* test(){
console.log("start");
yield;
console.log("finish");
}
var test1 = test();
//須將函數(shù)聲明為變量使用此方法
test1.next();
test1.next();
每個(gè).next()
執(zhí)行yield
分割的一段代碼,第一個(gè)test1.next();
執(zhí)行至yield
之前停止打印出"start"袁翁,第二個(gè)test1.next()
執(zhí)行之后的代碼冷溃,打印出"finish"
-
析構(gòu)表達(dá)式
- 針對(duì)對(duì)象
在ts中若想一對(duì)一地將含有多個(gè)屬性的對(duì)象的函數(shù)返回值賦予多個(gè)變量時(shí),可使用析構(gòu)表達(dá)式梦裂,代碼如下
- 針對(duì)對(duì)象
function programmer(){
return {
name:"Tom",
skill:{
skill1:"TypeScript",
skill2:"AngularJs"
},
age:18
}
}
var {name,age} = programmer();
//此簡(jiǎn)寫(xiě)方法須滿足變量名與函數(shù)中的屬性名對(duì)應(yīng)相同
console.log(name,age);
//打印出Tom 18
var {name:name1,skill:{skill1:skills}} = programmer();
//此為變量名與函數(shù)中屬性名不相同的寫(xiě)法
console.log(name1,skills);
//打印出Tom TypeScript
轉(zhuǎn)譯后的js代碼如下
"use strict";
function programmer() {
return {
name: "Tom",
skill: {
skill1: "TypeScript",
skill2: "AngularJs"
},
age: 18
};
}
var _programmer = programmer();
var name = _programmer.name;
var age = _programmer.age;
console.log(name, age);
var _programmer2 = programmer();
var name1 = _programmer2.name;
var skills = _programmer2.skill.skill1;
console.log(name1, skills);
另外還可以在其中使用之前提過(guò)的Rest and Spread操作符拆分對(duì)象
var obj = {a:1,b:2,c:3,d:4};
var {a,b,...others}=obj;
//打印出1 2 {"c":3,"d":4} *將后兩個(gè)屬性打包進(jìn)others中
轉(zhuǎn)譯后js代碼
"use strict";
function _objectWithoutProperties(obj, keys) { var target = {}; for (var i in obj) { if (keys.indexOf(i) >= 0) continue; if (!Object.prototype.hasOwnProperty.call(obj, i)) continue; target[i] = obj[i]; } return target; }
var obj = { a: 1, b: 2, c: 3, d: 4 };
var a = obj.a;
var b = obj.b;
var others = _objectWithoutProperties(obj, ["a", "b"]);
console.log(a, b, others);
- 針對(duì)數(shù)組
在數(shù)組中取值上面的方法一樣成立
var arr = [1,2,3,4];
var [num1,num2]=arr;
//注意此處是中括號(hào)
console.log(num1,num2);
//打印1 2
var [,,num3,num4]=arr;
console.log(num3,num4);
//打印3 4 用逗號(hào)空出對(duì)應(yīng)位置即可跳躍取值
var [num5,,num6]=arr;
console.log(num5,num6);
//打印1 3
var [num7,...others]=arr;
console.log(num7,others);
//打印1 [2,3,4] *此時(shí)將剩余的三個(gè)數(shù)打包放進(jìn)others中
轉(zhuǎn)譯后的js代碼如下
"use strict";
var arr = [1, 2, 3, 4];
var num1 = arr[0];
var num2 = arr[1];
console.log(num1, num2);
var num3 = arr[2];
var num4 = arr[3];
console.log(num3, num4);
var num5 = arr[0];
var num6 = arr[2];
console.log(num5, num6);
var num7 = arr[0];
var others = arr.slice(1);
console.log(num7, others);
-
函數(shù)表達(dá)式與循環(huán)
-
箭頭表達(dá)式
在ts中我們可以運(yùn)用箭頭表達(dá)式=>
來(lái)聲明一個(gè)匿名函數(shù)
var test = arg1=>arg1;
//單個(gè)參數(shù)可以不加小括號(hào)
var sum = (arg1,arg2) =>arg1+arg2;
//單行聲明可以不加大括號(hào)
var sum2 = (arg1,arg2)=>{
return arg1+arg2
}
//多行寫(xiě)法
轉(zhuǎn)譯后js代碼
"use strict";
var test = function test(arg1) {
return arg1;
};
var sum = function sum(arg1, arg2) {
return arg1 + arg2;
};
var sum2 = function sum2(arg1, arg2) {
return arg1 + arg2;
};
這樣看其實(shí)箭頭表達(dá)式只是比原來(lái)的聲明方法簡(jiǎn)便些而已,其實(shí)不然盖淡。箭頭表達(dá)式真正強(qiáng)大的是可以很輕松的化解之前一直困擾我們得this的作用域問(wèn)題
下面一段代碼在js中是打印不出東西的
function Person(x){
this.name=x;
setInterval(function(){
console.log(this.name)
},1000)
}
var man = new Person('zhangsan');
//setInterval中的this指向的是全局對(duì)象window而不是我們所創(chuàng)建的對(duì)象
而應(yīng)用箭頭表達(dá)式就可以輕松解決作用域的問(wèn)題
function Person(x){
this.name=x;
setInterval(()=>{
console.log(this.name)
},1000)
}
var man = new Person('zhangsan');
//每一秒打印出一個(gè)zhangsan
轉(zhuǎn)譯后js代碼中可以看出實(shí)際上是ts幫我們寫(xiě)了糾正this這段代碼
function Person(x) {
var _this = this;
this.name = x;
setInterval(function () {
console.log(_this.name);
}, 1000);
}
var man = new Person('zhangsan');
- 新循環(huán)for of(與forEach年柠、for in對(duì)比)
var arr = [1, 2, 3, 4];
arr.attr = 'number 5';
//這里在ts會(huì)報(bào)錯(cuò) 但其實(shí)可以運(yùn)行
arr.forEach((value,key) => console.log(value,key));
//打印出1,0|2,1|3,2|4,3
for (var i in arr) {
console.log(i);
};
//打印出1,2,3,4,attr
for (var n of arr) {
console.log(n);
}
//打印出1,2,3,4
for (var n of arr) {
if(n>2)break
console.log(n);
}
//打印出1,2
for of與另兩者最大的區(qū)別就在于for of會(huì)忽視掉循環(huán)中的非數(shù)字元素(for in不會(huì)),且可以打斷(forEach不可打斷)
-
面向?qū)ο筇匦?/h4>
-
類的聲明
在ts中有一種專門(mén)的用class
引導(dǎo)的類聲明,例如下面的Programmer類聲明
class Programmer{
name;
skill;
work(){
console.log("coding....")
}
};
var pro1 = new Programmer();
pro1.name = 'zhang san';
pro1.skill = 'TS';
pro1.work();
//轉(zhuǎn)譯后js代碼
var Programmer = (function () {
function Programmer() {
}
Programmer.prototype.work = function () {
console.log("coding....");
};
;
return Programmer;
}());
var pro1 = new Programmer();
pro1.name = 'zhang san';
pro1.skill = 'TS';
pro1.work();
以上的代碼中冗恨,聲明了一個(gè)Programmer類答憔,其中含有name,skill兩個(gè)屬性和work方法掀抹,而其調(diào)用方式與js中一樣虐拓。我們可以看到轉(zhuǎn)譯后,work()實(shí)際上是定義在原型上的方法傲武。
* 類的訪問(wèn)權(quán)限
在類的聲明同時(shí)蓉驹,可以用public
private
protected
對(duì)其中屬性和方法的訪問(wèn)權(quán)限進(jìn)行聲明
圖中分別用三個(gè)訪問(wèn)操作符聲明了3個(gè)屬性和一個(gè)方法,聲明private和protected的屬性和方法在外部揪利,也就是class代碼的外面調(diào)用是會(huì)報(bào)錯(cuò)的态兴,而在內(nèi)部work()方法可以任意調(diào)用屬性。
總結(jié)來(lái)說(shuō)
public
操作符聲明的可以在任意地方使用疟位,也是不聲明時(shí)的默認(rèn)操作符瞻润;private
操作符會(huì)使其只可在class內(nèi)部被調(diào)用;而protected
操作符則在class內(nèi)部和該類的后代繼承元素上可以使用
public | protected | private | |
---|---|---|---|
外部 | √ | × | × |
后代 | √ | √ | × |
內(nèi)部 | √ | √ | √ |
需要注意的是:這段代碼只是在書(shū)寫(xiě)階段會(huì)引發(fā)報(bào)錯(cuò)甜刻,而使用時(shí)不會(huì)有任何問(wèn)題绍撞,因?yàn)檗D(zhuǎn)譯成js后并不存在這些功能
-
類構(gòu)造器
聲明類時(shí)可用constructor
關(guān)鍵字在類內(nèi)部聲明一個(gè)函數(shù),成為構(gòu)造器函數(shù)得院,此函數(shù)只可在函數(shù)內(nèi)部應(yīng)用傻铣,當(dāng)我們對(duì)類實(shí)例化的時(shí)候該函數(shù)就會(huì)運(yùn)行一次
-
類構(gòu)造器
class Programmer {
constructor() {
console.log('coding');
}
//構(gòu)造器函數(shù)
};
var pro1 = new Programmer();
//打印一次coding
構(gòu)造器函數(shù)的一個(gè)重要用途就是規(guī)定一個(gè)類里的某些屬性必須在實(shí)例化時(shí)被傳入值,如下
class Programmer {
name;
constructor(name:string) {
console.log('coding by '+name);
}
};
//也可以像下面這么寫(xiě)
class Programmer {
constructor(public name:string) {
console.log('coding by '+name);
}
};
var pro1 = new Programmer();
//這行代碼會(huì)引發(fā)編輯器報(bào)錯(cuò)
var pro2 = new Programmer('zhangsan');
//打印 coding by zhangsan
-
類的繼承
ts中也有繼承類的關(guān)鍵詞extends
尿招,同js中一樣矾柜,子類通過(guò)extends
會(huì)繼承父類的所有方法和屬性,并可定義只屬于自身的方法和屬性
class Programmer{
name;
skill;
work(){
console.log("coding with "+this.skill)
}
};
class WebProgrammer extends Programmer{
no;
learn() {
console.log(this.no+' is learning TS')
}
}
var Wp1 = new WebProgrammer();
Wp1.skill = 'js';
Wp1.no = 1;
Wp1.work();
//打印 coding with js
Wp1.learn();
//打印 1 is learning Ts
-
構(gòu)造函數(shù)繼承
ts語(yǔ)法規(guī)定在子類里聲明構(gòu)造函數(shù)時(shí)就谜,必須要通過(guò)super
關(guān)鍵詞在其構(gòu)造函數(shù)內(nèi)部調(diào)用父類的構(gòu)造函數(shù)
class Programmer{
name;
skill;
constructor(name) {};
work(){
console.log("coding with "+this.skill)
}
};
class WebProgrammer extends Programmer{
no;
constructor(name:string,no:number) {
super(name);
this.no = no;
//在這里用super繼承了父類構(gòu)造函數(shù)的name屬性怪蔑,將name和no作為子類的兩個(gè)實(shí)例化時(shí)必須賦值的屬性
}
learn() {
console.log(this.no+' is learning TS')
}
}
var Wp1 = new WebProgrammer('zhangsan',1);
Wp1.skill = 'js';
Wp1.work();
Wp1.learn();
上面介紹的是用super
繼承父類的屬性,同樣父類的方法也可以繼承丧荐,下面是一個(gè)實(shí)例
class Programmer{
name;
skill;
constructor(name) { };
work(){
console.log("coding with "+this.skill)
}
};
class WebProgrammer extends Programmer{
no;
constructor(name:string,no:number) {
super(name);
this.no = no;
}
learn() {
super.work();
//繼承父類的work方法
this.learnAfterWork;
};
private learnAfterWork() {
//將該方法聲明為私有
console.log('learning sth')
};
}
var Wp1 = new WebProgrammer('zhangsan',1);
Wp1.skill = 'js';
Wp1.work();
//打印coding with js
Wp1.learn();
//打印coding with js,learning sth
Wp1.learnAfterWork();
//無(wú)法打印 因?yàn)榉椒╨earnAfterWork是私有的缆瓣,外部訪問(wèn)到
-
泛型
在ts中,可以用尖括號(hào)<>
對(duì)集合中元素的類型加以限制虹统,概括的云山霧繞弓坞,一看代碼便知
class Programmer{
name;
skill;
work(){
console.log("coding with "+this.skill)
}
};
class WebProgrammer extends Programmer{
no;
learn() {
console.log(this.no+' is learning TS')
}
};
var Wp: Array<Programmer> = [];
//聲明Wp數(shù)組里只能放入Programmer類的元素
Wp[0] = new Programmer();
//成功
Wp[1] = new WebProgrammer();
//成功 WebProgrammer也屬于Programmer
Wp[2] = 1;
//在ts中會(huì)報(bào)錯(cuò)
-
接口
ts中獨(dú)有的接口interface
用來(lái)形成一種約束,是的開(kāi)發(fā)者在創(chuàng)建應(yīng)用此接口的類或方法時(shí)必須要遵守接口中的代碼規(guī)則车荔,其有兩種典型的使用方式渡冻,并且語(yǔ)法與聲明類十分相似- 1:對(duì)類的屬性進(jìn)行約束
interface IProgrammer{
name: string;
age: number;
};
class Programmer{
constructor(public config: IProgrammer) {}
//構(gòu)造函數(shù)中限制屬性要應(yīng)用IProgrammer接口約束
};
var p1 = new Programmer();
//報(bào)錯(cuò)
var p2 = new Programmer('zhangsan',18);
//報(bào)錯(cuò)
var p3 = new Programmer({
name: 'zhangsan',
age:18
});
//正確調(diào)用方法:傳入一個(gè)帶有規(guī)定屬性的對(duì)象
- 2:對(duì)方法進(jìn)行約束
對(duì)方法進(jìn)行約束需要用到implements
關(guān)鍵詞,它規(guī)定被約束的方法內(nèi)必須實(shí)現(xiàn)接口中的函數(shù)
interface IProgrammer{
useTool();
};
class JsProgrammer implements IProgrammer{
useTool(){
console.log('use JS')
}
};
class TsProgrammer implements IProgrammer{
useTool(){
console.log('use TS')
}
}
例子中若在聲明的方法中沒(méi)有實(shí)現(xiàn)useTool方法則會(huì)引發(fā)報(bào)錯(cuò)
-
模塊
在ts中忧便,每個(gè)ts文件就相當(dāng)于一個(gè)模塊而在文件內(nèi)部用export
,import
兩個(gè)關(guān)鍵字進(jìn)行導(dǎo)出族吻、導(dǎo)入模塊。只有在其他模塊已經(jīng)導(dǎo)出的元素才可以在其他模塊中導(dǎo)入
例:在同一個(gè)目錄下建立兩個(gè)ts文件——export.ts和import.ts
export.ts代碼
export class klass1 { };
class klass2 { };
export var x1;
var x2;
export function func1() { };
function func(){};
//沒(méi)有加export的就是沒(méi)有輸出
import.ts代碼
import {klass1,x1,func1} from "export.ts";
x1=1;
var k1=new klass1;
func1();
//這里是取不到export.ts中沒(méi)有導(dǎo)出的klass2,x2,func2的
- 注解
ts注解是提供給指定的工具和框架使用的,為程序元素(類超歌,方法砍艾,變量)加上更直觀的的說(shuō)明,而與程序業(yè)務(wù)邏輯無(wú)關(guān)
例如angular2里的@component
(待研究.....)
- 類型定義文件
"那么在ts文件怎么應(yīng)用js中的那些庫(kù)和框架呢巍举?"
這時(shí)候就要用到類型定義文件xxx.d.ts
脆荷,如將jquery的類型定義文件index.d.ts放到ts同目錄下,這時(shí)jquery的接口就已經(jīng)全部導(dǎo)出了懊悯,可以直接在ts文件中調(diào)用
而尋找各種各樣工具的類型定義文件就要用到