美文网首页
ts与面向对象

ts与面向对象

作者: LOVE小狼 | 来源:发表于2018-08-09 18:22 被阅读390次

    一. 简介

      Typescript是一门开源的编程语言,由Microsoft开发维护,首次发布于2012年10月。Typescript是一门静态类型语言,是ECMAScript的超集,支持javascript所有语法,并提供了更多其它特性,下图描述了ts与js之间的关系。

    关系图

    二. 类型系统

    1. 强类型,用于规范代码
    let a: String = 1;  // 报错,1不可转为String
    
    1. 类型检查,ts有自己的编译器,采用静态代码分析技术来避免名称错误等问题,避免运行时错误。
    let a: String = 1; 
    a.hehe();// 报错,a中没有hehe方法
    
    1. 天然的api规范
      注:规范本身不该是语言限定,而应该是人为限定

    2.1 基础数据类型

    • boolean

    • string

    • number

    • Array
      与js中有所区别,强类型下的Array中元素类型声明后,数组中所有类型均一致

    • Tuple
      元组类型允许表示一个已知元素数量和类型的数组,各元素的类型不必相同

    // Declare a tuple type
    let x: [string, number];
    // Initialize it
    x = ['hello', 10]; // OK
    // Initialize it incorrectly
    x = [10, 'hello']; // Error
    
    • Enum
      枚举类型的作用在于为某些特定的数字提供语义
    enum Color {Red, Green, Blue}    // 默认从第一个变量开始的值为0,1,2
    let c: Color = Color.Green;  // 值为1
    
    enum Color {Red = 'red', Green = 'green', Blue = 'blue'}    // 显示赋值
    let c: Color = Color.Green;  // 值为red
    
    • Any

    • void

    • null

    • undefined

    • never
      用不上别学了

    • Symbol

    • Object

    2.2 结构化数据类型

    1. class
    2. interface
    • 明确变量结构,字段名称类型必须满足接口结构
    // 接口声明
    interface Point2D {
        x: number
        y: number
    }
    
    let xy: Point2D = {
        x: 1,
        y: 2,   
        // z: 2    编译不通过,z属性不Point2D接口字段
    } 
    
    • 希望部分字段严格遵守时可使用可选属性
    interface Point2D {
        x: number
        y?: number
    }
    
    let xy: Point2D = {
        x: 1,
        // y: 2    编译通过,y属性为可选属性
    } 
    
    • 除了变量的类型可控以外,还可以控制变量的是否可写
    interface Point2D {
        readonly x: number
    }
    
    let xy: Point2D = {
        x: 1,
    }
    xy.x = 2  //   x为只读属性,不可赋值
    
    • 类型推导
      如果不显示声明类型,编译器会根据变量的值类型来推断出该变量应该属于何种类型.
    let num = 6
    num = '6'    // 编译不通过,num在赋值为6后被推断为number类型,不可赋值字符串
    
    • 类型变量——泛型
    // 想要一个值为数字的节点
    class Node {
      value: number 
    }
    let node1: Node = new Node()
    // 又想要一个值为字符串的节点
    class Node {
      value: string 
    }
    let node2 = new Node()
    // 避免各种值类型的节点可能会考虑使用any
    class Node {
      value: any  // 失去了静态类型的优势 
    }
    let node2 = new Node()
    // 范型的使用方式
    class Node <T> {
      value: T  
    }
    let node3 = new Node<string>()
    let node4 = new Node<number>()
    

    三. 面向对象

    3.1 封装

      一切从对象开始,对象内部可通过private protected public(默认值)来限定对象属性的访问权限。

    • private:限定仅可在当前类内部使用,不对外暴露
    class Person {
        name
        private age
        constructor(name, age) {
            this.name = name
            this.age = age
        }
    }
    
    let person = new Person('hehe', 2)
    console.log(person.age)    // 属性age为私有属性,只能在类'Person'中访问
    
    • protected:限定当前类属性只能在当前类或其子类中使用
    class Person {
        protected name
        private age
        constructor(name, age) {
            this.name = name
            this.age = age
        }
    }
    
    let person = new Person('hehe', 2) 
    console.log(person.name)  // name属性受保护,只能在类'Persion'及其子类中访问
    
    class Man extends Person {
        name
        constructor() {
            super('1', 2)
            console.log(super.name)    // 子类中可正常访问
        }
    }
    
    • public:当前类属性可随意访问
    • 特权方法
      对于private与protected修饰的属性想要被外界使用时,建议在类内部定义getter与setter方法,通过将方法暴露到外面实现对属性的操作,这种方法叫做特权方法。
    class Person {
        protected name: string
        private age: number
        constructor(name, age) {
            this.name = name
            this.age = age
        }
        getName() {
           return this.name
        }
        setName(name: string) {
           this.name = name
        }
    }
    let person: Person = new Person()
    console.log(person.getName())
    

    3.2 继承

    • super:子类继承父类后必须使用super实例化父类,达到继承父类属性的目的
    • 重写:子类中声明与父类相同方法时可重写父类方法
    class Person {
        protected name
        private age
        constructor(name, age) {
            this.name = name
            this.age = age
        }
    
        say(word) {     // 父类say方法
            console.log('Persion:', word)
        }
    }
    
    let person: Person = new Person('hehe', 2)
    
    class Man extends Person {
        name
        constructor() {
            super('hehe', 2)
        }
        say(word) {  // 子类重写父类say方法
            console.log('Man:', word)
        }
    }
    
    let man: Person = new Man()
    man.say('hahaha')  //  Man:hahaha
    
    • 父类型可以指向子类型
      类似家谱一样,继承的子类型也是父类型
    class Person {}
    class Man extends Person {}
    
    let man: Person = new Man()   // 创建Man类的对象,类型声明为Person
    
    • 实现相同接口的类型可以看作是同一类型
    interface DaoService {
        add(): number;
    }
    
    class DaoServiceImpl1 implements DaoService {
        add() {
           return 1 
        }
    }
    
    class DaoServiceImpl2 implements DaoService {
        add() {
           return 2
        }
    }
    
    let daoService1: DaoService = new DaoServiceImpl1()
    let daoService2: DaoService = new DaoServiceImpl1()
    console.log(daoService1.add())     //  1
    console.log(daoService2.add())     //  2
    

    3.3 多态

    3.3.1 概念

    • 同一类型的同一属性或方法有不同的表现
    • 是强类型下代码更灵活的必要机制

    3.3.2 多态的使用条件

    • 继承
    • 重写
    • 父类引用指向子类对象

    3.4 被说烂的概念

    并不是使用了封装继承的代码就是面向对象


    路由模块拆分

    路由配置


    image.png

    路由配置的处理


    image.png
    路由扩展:添加了一个custom的回调方法用来处理扩展问题。

    问题

    1. 类的划分问题:RouteBase类是为每个路由模块服务的,只有在出现特殊的路由模块时才需要继承重写该类方法,当前业务场景下不太可能出现一整个路由模块都进行统一的处理。
    2. 主流程中存在多余的逻辑判断:主流程留下了变动的可能性,应将该处变化点封装到其它位置。


      主流程

    3.4.1 主流程(需要高度抽象)

    • 拿到各模块的路由配置数据(获取数据)
      配置数据的多样性如何处理??
      路由配置可以抽象为一个类,每个对象拥有自己的数据
    • 将配置数据进行处理(处理数据)
      配置数据处理方式的多样性如何处理??
      路由配置类通过子类重写来实现配置数据处理的多样性
    • 处理后的数据返回(返回数据)

    3.4.2 流程中的每一步需要具有一定抽象性

    流程步骤中的对象(父类)与方法(接口)都不应该依赖于具体,应该依赖抽象

    四. 总结

      ts通过强类型与面向对象机制保证了代码即健壮又灵活,其编程思想更能提高我们的视野,为了更好的保护自己优秀的代码,建议大家多多尝试。

    推荐视频:angularjs问道前端开发
    https://www.imooc.com/learn/556

    相关文章

      网友评论

          本文标题:ts与面向对象

          本文链接:https://www.haomeiwen.com/subject/avuqbftx.html