天天看點

ts:學習總結TS第一個TS檔案

TS

TypeScript是什麼

TypeScript是JavaScript的超集。(比JS多了一個類型系統)

與JS相比的優勢:

.類型化思維方式,使得開發更加嚴謹,提前發現錯誤,減少改Bug時間

.類型系統提高了代碼可讀性,并使維護和重構代碼更加容易

.補充了接口、枚舉等開發大型應用時JS缺失的功能

安裝解析TS的工具包

-在vscode終端

-指令:

npm install -g typescript
           

typescript:就是用來解析ts的工具包,提供了tsc指令,實作了TS->JS的轉化

第一個TS檔案

建立第一個ts檔案

-建立一個檔案,以.ts結尾

-寫入代碼

console.log('hello ts')
           

在終端中運作

tsc .\hello.ts
           

**報錯:tsc:無法加載檔案,是因為在此系統禁止運作腳本

解決:以管理者身份打開powershell,輸入以下指令,再敲Y,就可以了

set-ExecutionPolicy RemoteSigned
           

執行完成後生成.js檔案

-執行js檔案

node hello.js
           

在視窗中列印出hello ts

簡化執行ts步驟

使用ts-node包,“直接”在Node.js中執行ts代碼

-安裝ts-node

npm i -g ts-node
           

-可以直接用ts-node 指令運作ts檔案

注釋

-單行注釋 // 快捷鍵:ctrl+/

-多行注釋 快捷鍵:shift+alt+a

輸出語句

作用:在終端列印資訊

變量

變量:存儲資料的容器,并且是可以變化的

變量的使用

.聲明變量并制定類型

let age:number
           

.給變量指派

age=19
           

或:聲明變量的同時就指派

let age:number = 19
           

類型注解

類型注解:是一種為變量添加類型限制的方式。約定了什麼類型,就隻能給變量賦什麼類型的值。

命名規則

變量名稱隻能出現:數字、字母、下劃線、$,且不能以數字開頭

**命名規範:駝峰命名法:首字母小寫,後面每個單詞首字母大寫

資料類型

-原始資料類型(基本資料類型)

number/string/boolean

/undefined:聲明但未指派的變量

/null:聲明了變量并且指派null,值為null

-對象類型(複雜資料類型)

-數組類型(array)

1.第一種

var arr:number[] = [11,22,33]
           

2.第二種定義數組的方式

var arr:Array<number>=[11,22,33]
           

3.第三種

var arr3:any[] = [11,22,33]
           

-元祖類型(tuple) :屬于數組的一種, 可以給數組中任意位置指定類型

let arr:[number,string] = [123,'this is ts']
           

-枚舉類型(enum)

enum Flag (success=1,error=2)
let f:Flag = Flag.error;
console.log(f)  //如果沒有給這個值指派,則列印的是下标
           
-任意類型(any) 變量可以為任意類型
      
var num:any =123;
           

用處:

var oBox:any = document,getElementById('box')
oBox.style.color='red'
           

-null和undefined(never類型)

var num:number | null |undefined   //一個元素可以為多個類型
           

方法沒有傳回值

function run():void{
  console.log('run')
}
           

-never類型:是其他類型(包括null和undefined)的子類型,代表從不會出現的值

聲明never的變量隻能被never類型所指派

var a:undefined;
a = undefined;
           

運算符

算術運算符 + - * /

**加号+還可以實作字元串拼接

指派運算符

遞增、遞減運算符

比較運算符

邏輯運算符

函數

1.函數聲明法

function run():string{
  return 'run';
}
           

2.匿名函數法

var fun2 = function():number{
    return 123;
}
           

3.ts中定義方法傳參 (函數參數指定類型,函數也要指定類型)

function getInfo(name:string,age:number):string{
  return `${name}---${age}`;
}
           

方法可選參數

es5裡面方法的實參和形參可以不一樣,但是ts中必須一樣,如果不一樣就需要配置可選參數

在參數後面加一個問号表示參數是可選的
function getInfo(name:string,age?:number):string{
  if(age){
    return `${name}---${age}`
  }else{
    return `${name}---年齡保密`;
  }
}
alert(getInfo('zhangsan'))
           

預設參數

es5裡面沒設定預設參數,es6中可以有可選參數

可選參數必須配置到參數的最後面

function getInfo(name:string,age:number=20):string{
  if(age){
    return `${name}---${age}`
  }else{
    return `${name}---年齡保密`;
  }
}
           

剩餘參數

三點運算符,接收新傳遞過來的值

原來是這樣的:

function sum(a:number,b:number,c:number,d:number):number{
  return a+b+c+d;
}
           

可以用一個result來存傳遞過來的參數

function sum(...result:number[]):number{
  var sum = 0;
  for(var i=0;i<result.length;i++){
    sum+=result[i];
  }
  return sum;
}
alert(sum(1,2,3,4))
           

或者:

function sum(a:number,...result:number[]):number{
  var sum = 0;
  for(var i=0;i<result.length;i++){
    sum+=result[i];
  }
  return sum;
}
alert(sum(1,2,3,4))
           

就把第一個參數指派給a

函數重載

通過為同一個函數提供多個函數類型定義來實作多種功能的目的

function getInfo(name:string):string;
function getInfo(name:number):number;
function getInfo(name:any):any{
  if(typeof str==='string'){
    return '我叫:'+str;
  }else{
    return '我的年齡是'+str;
  }
}
//如果console.log(true) 則會報錯,為了規範寫法,規定傳入的值得類型
           

箭頭函數

主要在setTimeout中,把參數從functiong改為箭頭函數

箭頭函數中的this指向上下文

es中類的定義

1.最簡單的類

function Person(){
  this.name='張三';
  this.age=20;
  this.run()=function(){
    alert('在運動');
  }
}
var p = new Person();
alert(p.name);
           

2.構造函數和原型鍊裡面增加方法

function Person(){
  this.name='張三';
  this.age=20;
  this.run()=function(){
    alert('在運動');
  }
}
Person.prototype.sex='男';  //直接在prototype上挂載屬性和方法
Person.prototype.work=function(){
  alert('在工作')
}
var p = new Person();
alert(p.name);
           
原型鍊上的屬性會被多個執行個體共享,構造函數不會

靜态方法

Person.getInfo=function(){}
           

Web類 繼承Person類 原型鍊+對象冒充的組合繼承模式

function Web(){
  Person.call(this);  //對象冒充實作繼承
}
var w = new Web();
w.run();  //正确
w.work(); //錯誤
           
對象冒充可以繼承構造函數裡面的屬性和方法,但是不能繼承原型鍊上面的屬性和方法

Web類 繼承Person類 原型鍊+對象冒充的組合繼承模式

Web.prototype = new Person()  //原型鍊實作繼承
var w = new Web();
w.run();  //正确
w.work();  //正确
           

原型鍊實作繼承的問題

function Person(name,age){
  this.name='張三';
  this.age=20;
  this.run()=function(){
    alert(this.name+'在運動');
  }
}
Person.prototype.sex='男';  //直接在prototype上挂載屬性和方法
Person.prototype.work=function(){
  alert(this.name+'在工作')
}
function Web(name,age){
  
}
Web.prototype = new Person();
var w = new Web('趙四',20);
w.run()  //輸出undefined在運動
           
執行個體化子類的時候沒法給父類傳參
function Web(name,age){
  	Person.call(this,name,age) //對象冒充繼承,執行個體化子類可以給父類傳參
}
Web.prototype = new Person();
var w = new Web('趙四',20);
w.run()  //輸出undefined在運動
           

原型鍊+對象冒充的另一種方式

function Web(name,age){
  	Person.call(this,name,age) //對象冒充繼承,執行個體化子類可以給父類傳參
}
Web.prototype = Person.prototype;
var w = new Web('趙四',20);
w.run()  //輸出undefined在運動
           

typescript中的類

class Person{
  name:string;
  constructor(n:string){  //構造函數  執行個體化類的時候觸發的方法
    this.name=n;
  }
  run():void{
    alert(this.name);
  }
}
var p = new Person('張三');
p.run();
           

執行個體化的時候先将'張三'指派給了constructor中的n,觸發構造函數,将n指派給了name屬性,在run方法中就可以拿到name的值,列印出name的值。

定義類,定義類的方法,擷取屬性,改變屬性的值

class Person{
  name:string;
  constructor(n:string){  //構造函數  執行個體化類的時候觸發的方法
    this.name=n;
  }
  getName():string{
    return this.name;
  }
  setName(name:string):void{
    this.name = name;
  }
}
var p = new Person('張三');
p.getName();
p.setName('李四');
           

ts中的繼承

還是主要通過extends和super實作

class Person{
  name:string;
  constructor(name:string){
    this.name = name;
  }
  run():string{
    return `$(this.name)在運動`
  }
}
class Web extends Person{   
  constructor(name:string){
    super(name);
  }
}
var w = new Web('李四');
w.run();
           
不僅要繼承類,還要用super繼承裡面的參數

思路:new w的時候,把’李四‘傳給Web中的constructor,然後通過super調用父類的構造函數,将name傳給Person中的constructor,父類接收到name為'李四',然後w在調用run方法的時候列印出父類的name李四。

super相當于初始化父類的構造函數

ts中繼承的探讨:父類的方法和子類的方法一緻

一緻的時候先找子類的方法,子類沒有這種方法再去找父類

類裡面的修飾符

ts裡面定義屬性的時候提供了三種修飾符

public:共有,在類、子類、類外面都可以通路(預設)

protected:保護類型,在類、子類裡面可以通路,在類外面無法通路

private:私有,在類裡面可以通路,子類、類外面無法通路

靜态屬性和方法

es5中的靜态方法

function Person(){
  this.run1 = function(){  //執行個體方法
  }
}
Person.name='哈哈哈';
Person.run2 = function() //靜态方法
function $(element){
  return new Base(element);
}
$.get=function(){};
function Base(element){
  this.element=擷取dom節點;
  this.css=function(arr,value){   //執行個體方法
    this.element.style.arr = value;
  }
}
$('#box').css('color','red');  
$.get('url',function(){})   //靜态方法
           

$('#box')相當于new Base(element),通過函數傳入dom節點,調用Base中的執行個體設定css 樣式

ts中的靜态方法

class Person{
  	public name:string;
  	public age:number = 20;
  	static sex ='男';
  	constructor(name:string){
		this.name = name;
	}
	run(){  //執行個體方法,執行個體化的時候調用的方法
      alert(`${this.name}在運動`)
	}
	work(){
      alert(`$(this.name)在工作`)
	}
	static print(){  //加上static關鍵字為靜态方法
      alert('print方法')
      alert('print方法'+this.age)//錯誤,靜态方法無法直接調用類裡面的屬性
      alert('print方法'+Person.sex) //正确,換成靜态的屬性
	}
}
Person.print();
           

多态

多态:父類定義一個方法不去實作,讓繼承它的子類去實作,每一個子類有不同的表現

多台屬于繼承

class Animal{
  name:string;
  constructor(name:string){
    this.name=name;
  }
  ear(){  //不知道吃的是什麼
    console.log('吃的方法');
  }
}
class Dog extends Animal{
  constructor(name:string){
    super(name);
  }
  ear(){
    return this.name+'吃糧食';
  }
}
class Cat extends Animal{
  constructor(name:string){
    eat(){
      return this.name+'吃老鼠'
    }
  }
}
           

抽象類

用abstract關鍵字定義抽象類和抽象方法,抽象類中的抽象方法不包含具體實作,并且必須在派生類中實作

抽象方法隻能放在抽象類中

抽象類和抽象方法用來定義标準,Animal這個類要求它的子類必須包含eat方法

abstract class Animal{
	public name:string;
	constructor(name:string){
      this.name = name;
	}
  	abstract eat():any;
  	run(){};//不是抽象方法子類可以不實作
}
var a = new Animal() //錯誤,抽象類主要給子類提供一個基類

class Dog extends Animal{
  constructor(name:string){
    super(name);
  }
  eat(){   //在抽象類的子類中必須實作抽象類中定義的方法
    console.log(this.name+'吃糧食')
  }
}
var d = new Cat('小花貓')
           

接口

作用:限制和規範。不關心類的内部狀态資料,也不關心這些類裡方法的實作細節,隻規定這批類裡必須提供某些方法,提供這些方法的類就可以滿足實際需要。

定義:

interface 接口名稱{

​ 屬性:類型;

}
           

接口的可選屬性 屬性?:類型

函數類型接口

作用:對方法傳入的參數以及傳回值進行限制,也可以進行批量限制

加密的函數類型接口

interface encrypt{

(key:string,value:string):string;

}

var md5:encrypt=funciont(key:string,value:string):string{

return key+value;

}
           

可索引接口

數組、對象的限制(不常用)

interface UserObj{
  [index:string]:string
}
var arr:UserObj={name:'張三'}
           

類類型接口

對類的限制 和抽象類有點類似

interface Animal{
  name:string;
  eat(str:string):void;
}
class Dog implements Animals{
  name:string;
  constructor(name:string){
    this.name = name;
  }
  eat(){
	console.log('吃糧食')
}
}
           
*在Dog中的eat可以不傳參數,但是不能沒有eat()方法,傳參數的話必須得傳stringL類型

接口擴充 :接口可以繼承接口

interface Animal{
	eat():void;
}
interface Person extends Animal{
  word():void;
}
class Web implements Person{
  public name:string;
  constructor(name:string){
    this.name = name;
  }
  eat(){
    console.log(this.name+'喜歡吃饅頭');
  }
  work(){
    console.log(this.name+'寫代碼');
  }
}
           
*要實作父類接口定義的屬性和方法

泛型

作用:解決接口方法的複用性,一級對不特定資料類型的支援(類型校驗)

引入:

如下是一個傳回字元串類型的函數和一個傳回數字類型的函數

function getData(value:string):string{
  return value;
}
functiong getData(value:number):number{
  return value;
}
           

這樣會很備援,雖然可以寫成如下的函數

function getData(value:any):any{
  return value;
}
           

但是傳入的參數類型和傳回的參數類型不一緻,沒有類型校驗

是以出現了泛型:可以支援不特定的資料類型,要求:傳入的參數和傳回的參數一緻

function getData<T>(value:T):T{
  return value;
}
           
T表示泛型,具體什麼類型是調用這個方法的時候決定的

調用:

getData<string>('1234321')      

錯誤的調用:

getData<number>('1234321')      

注意:在這裡傳入什麼傳回什麼,也就是參數中的value和return中的value應該一緻,否則應該寫成如下代碼

function getData<T>(value:T):any{
	return value;
}
           

泛型類

比如有個最小堆算法,需要同時支援傳回數字和字元串兩種類型,通過類的泛型來實作

class MinClas<T>{
	public list:T[]=[];
	add(value:T):void{
      this.list.push(value);
	}
	min():T{
      var minNum=this.list[0];
      for(var i=0;i<this.list.length;i++){
        if(minNum>this.list[i]){
          minNum = this.list[i];
        }
      }
      return minNum;
	}
}
var m1 = new MinClas<number>();  //執行個體化類 并制定了類的T代表的是類型number
m1.add(1);
m1.add(3);
m1.add(2);
console.log(m1.min());  //輸出1
           

泛型接口

比如有一個函數類型接口

interface ConfigFn{
  (value1:string,value2:string):string;
}
var setData:ConfigFn=function(value1:string,value2:string):string{
  return value1+value2;
}
setData('name:','張三');
           

泛型接口方法一:

interface ConfigFn{
  <T>(value:T):T;
}
var getData:ConfigFn=function<T>(value:T):T{
  return value;
}
getData<string>('張三');
           

泛型接口方法二:

interface ConfigFn<T>{
  (value:T):T;
}
function getData<T>(value:T):T{
  return value;
}
var myGetData:ConfigFn<string> = getData;
myGetData('20');
           

應用:操作資料庫的泛型類

class MysqlDb<T>{
  add(info:T):boolean{
    console.log(info);
    return true;
  }
}
//定義User類,和資料庫進行映射
class User{
  password:string | undefined;
  username:string | undefined;
}
var u = new User();
u.username='張三';
u.password='123123';
var Db = new MysqlDb<User>();
Db.add(u);
           

子產品

可以把一些公共的功能單獨抽離成一個檔案作為一個子產品,子產品裡面的變量、函數、類等預設是私有的,如果我們要在外部通路子產品裡面的資料(變量、函數、類),我們需要通過export暴露子產品裡面的資料(變量、函數、類),暴露後我們通過import引入子產品就可以使用子產品裡面暴露的資料(變量、函數、類)

導出:export xxx();

導入:import {xxx as xxxxx} from 'where'

或者用export default 預設導出:每個子產品都可以有一個default導出,預設導出使用default關鍵字标記,并且一個子產品隻能夠有一個default導出,需要使用一種特殊的導入形式

導出:export default xxx();

導入:import xxx from 'where'

命名空間

内部子產品,主要用于組織代碼,避免命名沖突

子產品:ts的外部子產品的簡稱,側重代碼的複用,一個子產品可能會有多個命名空間

裝飾器

是一種特殊類型的聲明,能夠被附加到類聲明,方法,屬性或參數上,可以修改類的行為,通俗來說,裝飾器就是一個方法,可以注入到類、方法、屬性參數上來擴充類、屬性、方法、參數的功能

常見裝飾器:類裝飾器、屬性裝飾器、方法裝飾器、參數裝飾器

裝飾器寫法:普通裝飾器(無法傳參)、裝飾器工廠(可傳參)

裝飾器後面不需要加分号

類裝飾器

類裝飾器在類聲明之前被聲明(緊靠着類聲明),類裝飾器應用于類構造函數,可以用來監視、修改或替換類定義

1.擴充類的方法

普通裝飾器

function logClass(params:any){
  console.log(params);  //這裡的params就是目前類
  //給目前類追加屬性
  params.prototype.apiUrl = '動态擴充的屬性';
  params.prototype.run=function(){
    console.log('我是一個方法');
  }
}
@logClass()
class HttpClient{
  constructor(){
    
  }
  getData(){
    
  }
}
           

裝飾器工廠(傳遞參數)

function logClass(params:any){
//這裡的paramas是'hello'  target是目前類
  return function(target:any){
    console.log(target);
    console.log(params);
    target.prototype.apiUrl = params;
  }
}
@logClass('hello')
class HttpClient{
  constructor(){
    
  }
  getData(){
    
  }
}
           

在裝飾器工廠中相當于将'hello'傳給了params,将class HttpClient類傳給了target

2.重構構造函數

類裝飾器表達式會在運作時當做函數被調用,類的構造函數作為其唯一的參數,如果類裝飾器傳回一個值,它會使用提供的構造函數來替換類的聲明

function logClass(target:any){
  console.log(target);
  return class extends target{
    apiUrl:any = '我是修改後的資料'
    getData(){
      this.apiUrl=this.apiUrl +'----';
      console.log(this.apiUrl);
    }
  }
}
@logClass
class HttpClient{
  public apiUrl:string | undefined;
  constructor(){
    this.apiUrl = '我是構造函數裡面的apiUrl';
  }
  getData(){
    console.log(this.apiUrl);
  }
}
var http=new HttpClient();
http.getData();
//列印出 我是修改後的資料
           

屬性裝飾器

屬性裝飾器表達式會在運作時當作函數被調用,傳入下列2個參數

1.對于靜态成員來說是類的構造函數,對于執行個體成員是類的原型對象

2.成員的名字

function logProperty(params:any){
  return function(target:any,attr:any){
    console.log(target);
    console.log(attr);
    target[attr]=params;  //修改為定義裝飾器時傳入的值
  }
}
@logClass('xxx')   //裝飾器工廠
class HttpClient{
  @logProperty('http://baidu.com');  //将url修改為http://baidu.com
  public url:any | undefined;
  constructor(){
    
  }
  getData(){
    console.log(this.url);
  }
}
var http=new HttpClient();
http:getData();
//列印出 http://baidu.com
           

方法裝飾器

會被應用到方法的屬性描述符上,可以用來監視,修改或者替換方法的定義

方法裝飾會在運作時傳入下列3個參數:

方法裝飾器一:在方法裝飾器中修改目前的屬性和方法

1.對于靜态成員來說是類的構造函數,對于實力成員是類的原型對象

2.成員的名字

3.成員的屬性描述符

function get(params:any){
  return function(target:any,methodName:any,dec:any){
    console.log(target);
    console.log(methodName);
    console.log(dec);
    target.apiUrl='xxx';
    target.run=function(){
      console.log('run');
    }
  }
}
class HttpClient{
  public url:any | undefined;
  constructor(){
    
  }
  @get('http://123123')
  getData(){
    console.log(this.url);
  }
}
var http:any = new HttpClient();
http.run();
           

方法裝飾器二:修改目前方法中的參數

function get(params:any){
  return function(target:any,methodName:any,dec:any){
    console.log(target);
    console.log(methodName);
    console.log(dec.value);  //列印出目前的方法
    //将傳入的參數全改為字元串類型
    desc.value=function(...args:any[]){
      arts = args.map((value)=>{
        args = args.map(value)=>{
          return String(value);
        }
        oMethod.apply(this.args)
      })
    }
  }
}
class HttpClient{
  public url:any | undefined;
  constructor(){
    
  }
  @get('http://123123')
  getData(...args:any[]){
    console.log(args);
    console.log('我是getData裡面的方法')
  }
}
var http:any = new HttpClient();
http.getData(123,'xxx');
//列印出 ['123','xxx']
           

方法參數裝飾器

參數裝飾器表達式會在運作時當作函數被調用,可以使用參數裝飾器為類的原型增加一些元素資料,傳入下列3個參數:

1、對于靜态成員來說是類的構造函數,對于執行個體成員是類的原型對象

2、參數的名字

3、參數在函數參數清單中的索引

function logParams(params:any){
	return function(target:any,paramsName:any,paramsIndex:any){
      console.log(target);
      console.log(paramsName);
      console.log(paramsIndex);
	}
}
class HttpClient{
  public url:any | undefined;
  constructor(){
  }
  getData(@logParams('asdf'),asdf:any){
    console.log('我是getData裡面的方法')
  }
}
var http = new HttpClient();
http.getData
           

裝飾器執行順序:

屬性裝飾器>方法裝飾器>方法參數裝飾器(從後到前)>類裝飾器(從後到前)

繼續閱讀