2020-10-30Typescript(1.2)

2020-11-02  本文已影响0人  夏天的风2020

Typescript: 进入类型的世界

编程语言的类型:

1.动态类型语言 (Dynamically Typed Language)
    指的是在运行期间才会做数据类型检查的语言,
    在用动态类型语言编程的时候,不用给变量指定数据类型,一个变量可以是字符串,你也可以给它赋值变成一个数字,非常灵活
    第一次赋值给变量的时候,在内部将数据类型记录下来
    比如javascript,
    也就是说javascript写好的程序只有我们在运行的时候才能发现有啥错误,这种做法听起来有点危险
    所以前端发明了一系列静态类型代码的检查器,
    比如eslint,在编码期间就可以根据一系列的规则,提示一些有问题地方


 2.静态类型语言(Statically Typed Language)
    数据类型检查发生在编译的阶段,也就是所写程序要声明变量的数据类型。
    写程序要声明数据类型
    比如c,c++,java

TypeScript究竟是什么:

 Type指类型
    script指javascript,
    它的目标是把不看重类型的动态语言变成关注类型的静态语言
    1.官网口号javascript that scales可以理解为可扩展的javascript
    2.静态类型风格的类型系统
    3.从es6到es10甚至是esnext的语法支持
    4.兼容各种浏览器,各种系统,各种服务器,完全开源



    TypeScript 是 JavaScript 的超集,扩展了 JavaScript 的语法,
    因此现有的 JavaScript 代码可与 TypeScript 一起工作无需任何修改,
    TypeScript 通过类型注解提供编译时的静态类型检查。

为什么要学习typescript?

   1.程序更加容易
       函数或者方法输入输出的参数类型,外部条件等,
       动态语言的约束:需要手动调试等过程,
       有了typeScript:代码本身就可以回答上诉问题 
    2.效率更高
       在不同的代码块和定义中进行跳转
       代码自动保全
       丰富的接口提示
    3.更少的错误
       编译期间能够发现大部分错误
       杜绝大部分错误

安装typescript

   查看node及npm版本
    node -v  (至少10以上)
    npm -v

    安装:npm install -g typescript  (可以指定版本安装)
    查看版本:  tsc -v
    ts文件转换成js文件:  tsc filnaem.ts

# 函数

Typescript 文档地址:Functions

 在javascript中函数是一等公民,
    函数和其他类型的公民都一样,
    可以作为参数,可以存入数组,可以被另外一个函数返回,可以被赋值给另外一个变量
    
    由两部分构成:
    输入:传参来实现
    输出: 就是函数的返回结果
// 来到我们的第一个例子,约定输入,约定输出
function add(x: number, y: number): number {
  return x + y
}
add(1,2)  //参数必须按照规定类型添加
let result = add(1,2) //result也会变成number类型

// 可选参数(加个问号)
//在可选参数后面不可以再添加确定参数了,这样程序的判断就会发生混乱
function add(x: number, y: number, z?: number): number {
  if (typeof z === 'number') {
    return x + y + z
  } else {
    return x + y
  }
}
 //函数的表达式
 const add = (x:number,y:number,z?:number): number =>{
      if(typeof z === 'number'){
        return x+y+z
      }else{
       return x+ y
      }
   }
    //鼠标移到add上边,add获得了一个类型,
    //所以说,一个函数不仅输入和输出有类型,函数本身也是有类型的,
    //add是函数类型,
    //let add2: string = add  //会报错  函数类型和string类型是不适配的,
    //所以我们要声明一个完全一样的类型,

    在typescript中我们要这么写函数的类型,
    let add2: (x: number, y: number, z?:number) => number
    //(这个箭头不是es6的箭头函数,而是ts中声明函数类型返回值的方法。)
    //这个时候我们就是声明add2是number类型,

    //这个时候它们类型是一样的:let add2: (x: number, y: number, z?:number) => number = add  
    //不会报错


    //在ts中 凡是在冒号后面都是在声明类型,和实际的代码逻辑没什么关系


// 函数本身的类型
const add2: (x: number, y: number, z?:number) => number = add

Interface---Duck typing的概念可以描述各种类型,
它可以描述函数的类型么?
声明一个函数类型


// interface 描述函数类型
interface ISum {
  (x: number, y: number): number  //在Interface返回使用的是冒号
}
const sum2: ISum = sum
//(对比一下)
let add2: (x: number, y: number, z?:number) => number  //直接写返回使用的是箭头

//这时我们将add给它赋值为类型为ISum,类型也是完全的匹配
 let ada2: ISum = add

类 - Class

 在javascript的世界我们使用构造函数和原型链来实现继承,
 到了es6时代,总算出现了class的概念,虽然它的内部还是原型链的机制来实现,
 但是我们总算有了新的方法,从我们熟悉的面向对象的方式来审视这门语言了。
 typescript对类的支持可谓是更加丰富,除了es6,es7已有的内容,还添加了一些术语。

    //面向对象的一些术语:
    1.类 Class:定义了一切事物的抽象特点,包含它的属性和方法。就像是一张蓝图,
    //比如汽车是一个class,就像是一张造汽车的图纸。

    2.对象 Object,类的实例,通过new生成,有了蓝图我们就可以创造实实在在的汽车。
    //我们可以说一辆奥利Q5是汽车类的实例,也可以说一辆奔驰是汽车类的另一个实例。

    3.面向对象OOP三大特征:封装 继承  多态。
    封装:(Encapsulation):将对数据的操作细节隐藏起来,只暴露对外的接口。
          外界调用端不需要(也不可能)知道细节,就能通过对外提供的接口来访问该对象。

    继承(Inheritance):子类继承父类,子类除了拥有父类的所有特性外,还有一些更具体的特征。

    多态(Polymorphism):由继承而产生了相关的不同的类,对同一个方法可以有不同的响应。

    //比如猫和狗,他们都可以继承一次animal,但是他们分别实现了自己的eat,吃的方法,
    //此时针对某一个实例,我们无需了解它是猫或者狗,我们可以直接调用eat方法,
    //程序会自动判断出来应该如何执行某个方法。

//面向对象编程给人一种做上帝的感觉。

//举个例子:
//创建了一个类,叫animal,它是一个基本类。
class Animal {
  name: string;
  constructor(name: string) {  //里面有一个构造函数,构造函数是实例化执行的逻辑
    this.name = name          //一个方法
  }
  run() {
    return `${this.name} is running`
  }
}
const snake = new Animal('lily')
console.log(snake.run())  //输出lily  is runing

// 继承的特性
class Dog extends Animal {  //extends继承以后,自然有了父类属性和方法
  bark() {                 //创建了一个新的方法
    return `${this.name} is barking`
  }
}

const xiaobao = new Dog('xiaobao')
console.log(xiaobao.run())
console.log(xiaobao.bark())

 //多态
// 这里我们重写构造函数,注意在子类的构造函数中,必须使用 super 调用父类的方法,要不就会报错。
class Cat extends Animal {
  constructor(name) {
    super(name)            //constructor这里进行了一个重写
    console.log(this.name) //多添加了一行
  }
  run() {
    return 'Meow, ' + super.run()  //run方法也进行了重写
  }
}
const maomao = new Cat('maomao')
console.log(maomao.run())


 目前为止,我们都是讨论都是类的实例,实例上的属性和实例上的方法,
 那我们类上面有没有直接可以访问的属性和方法呢?

    //区别:不需要实例化,直接在类调用就可以

    class Cat extends Animal{
      static categories = ['mammal']  //创建了一个静态属性
      constructor(name){  
         super(name)
         console.log(this.name) 
       }
       run(){
         return 'Meow,'+super.run() 
       }
     }

    //console.log(Cat.categories())

    为什么要有静态属性或者方法呢?
    是因为这里面的定义和实例没太大关系,

    typeCsript怎么增强类?
    //三种访问修饰符,可以给类上的方法和属性提供权限管理,
    //有些内容是不愿意暴露给外部使用的

    public:修饰的属性或方法是公有的,可以在任何地方被访问到,默认所有的属性和方法都是public的
    private:修饰的属性或方法是私有的,不能在声明它的类的外部访问
    protected:修饰的属性或方法是受保护的,它和private类似,区别是它在子类中也是允许被访问的

    //有些属性只能读不能写,
    //readonly修饰符号 
    class Animal{
       readonly name: string;
       constructor(name: string){
         this.name = name
       }
       run(){
         return `${this.name} is running`
       }
     }

    //const snake = new Animal('lily)
    //snake.name = '123' //会报错  Connot addign to 'name' because it is a read-only

# 类与接口

类实现一个接口

 //继承的困境
 //类可以使用implements来实现接口


    //之前学过接口Interface,用于对对象的形状shape进行描述,
    //我们还用它描述了函数的类型,

    //本节介绍接口的另一个用途:对类的一部分行为进行抽象

    //在面向对象的世界中一个类只能继承自另外一个类,
    //有时候不同类之间会有一些共同的特新,使用子类继承父类的方法,很难来完成。
    //这时候我们就可以把这些特性提取成接口,然后用一个称之为implements的关键字来实现。
    //这样就大大提高了面向对象的灵活性。
//举个例子:
//创建一个称之为car的类,他有一个特性是switchRadio,

    class Car{
       switchRadio(trigger: boolean){
       }
     }

//现在又有一个蓝图出现了,负责创造一个手机类,手里类里面也有一个打开收音机的方法,
    class Cellphone{
      switchRadio(trigger: boolean){
       }
    }

    //我们发现这两个类有相同的特性,所以我们考虑把他们给提取出来,
    //如果用父类的形式,car和cellphone必须有一个合适的父类,
    //感觉很难找,
    //这是可以把这一个特性抽取成一个Interface,让这两个类都去实现它,


interface Radio {  //里面有一个switchRadio方法
  switchRadio(trigger: boolean): void;  //void关键字代表什么都不返回
}
class Car implements Radio {
  switchRadio(trigger) {
  }
}
class Cellphone implements Radio {
  switchRadio() {
  }
}
//这时我们implements就发挥契约的作用,
//告诉car和cellphone要去实现这个方法,
//删掉这个方法的时候就会报错

//通过Interface完成了逻辑功能的提取和验证,

一个小功能:检查电池的容量,手机有,汽车没有
//新创建一个接口
   interface Battery{
       checkBatteryStatus(): void;
   }

// 要实现多个接口,我们只需要中间用 逗号 隔开即可。
class Cellphone implements Radio, Battery {
  switchRadio() {
  }
  checkBatteryStatus() {

  }
}

接口之间还可以有继承的关系,注意这个是接口之间的继承,不是class之间的继承,
但其实是和class之间的继承是一样的,
新建一个接口
    interface RadioWithCellphone extends Radio{ //extends关键字继承
       checkBatteryStatus(): void
     }
    //RadioWithCellphone上边两个方法都有了,

    //可以替换上边的写法
    class Cellphone implements RadioWithCellphone{
       switchRadio(trigger){
       }
      checkBatteryStatus(){
      }
     }
  interface的一点点精髓:它仿佛是某种锲约可以定义和约束所有内容,
  比如object的样子可能用interface的方法来抽象类的属性和方法,
  还可以去定义一个函数类型,各种复杂的类型等等,
  所以这就是Duck typing的精髓,只要它走路像鸭子,叫起来像鸭子,
  不管你是什么东西,会用它来约束各种概念上毫不相关的内容。

  这节我们学会用interface和implements来抽象和验证类的属性和方法。
上一篇下一篇

猜你喜欢

热点阅读