类----Ts

一、基本概念

简单认知

  1. 类是现实世界或思维世界中的实体在计算机中的反映,它将数据(属性)以及这些数据上的操作(方法)封装在一起。
  2. 对象是具有类类型的变量。类和对象是面向对象编程技术中的最基本的概念。

类与对象的关系

  1. 类是对象的抽象,而对象是类的具体实例,是通过new classname产生的。
  2. 类是抽象的,不占用内存,而对象是具体的,占用存储空间。
  3. 类是用于创建对象的蓝图(规划,抽象)。

专业术语

  1. 面向对象(OOP)的三大特性:封装、继承、多态;
    • 封装(Encapsulation):将对数据的操作细节隐藏起来,只暴露对外的接口。外界调用端不需要(也不可能)知道细节,就能通过对外提供的接口来访问该对象,同时也保证了外界无法任意更改对象内部的数据;
    • 继承(Inheritance):子类继承父类,子类除了拥有父类的所有特性外,还有一些更具体的特性;
    • 多态(Polymorphism):由继承而产生了相关的不同的类,对同一个方法可以有不同的响应。比如 Cat 和 Dog 都继承自 Animal,但是分别实现了自己的 eat 方法;
  2. 存取器(getter & setter):用以改变属性的读取和赋值行为;
  3. 修饰符(Modifiers):修饰符是一些关键字,用于限定成员或类型的性质。比如 public 表示公有属性或方法;
  4. 抽象类(Abstract Class):抽象类是供其他类继承的基类,抽象类不允许被实例化。抽象类中的抽象方法必须在子类中被实现;
  5. 接口(Interfaces):不同类之间公有的属性或方法,可以抽象成一个接口。接口可以被类实现(implements)。一个类只能继承自另一个类,但是可以实现多个接口;

 

二、类和对象语法

类的定义

class Class_name {  //类名开头大写

// 类体

}

  1. 定义类的关键字为 class;
  2. 类体中声明类的成员(都是可选的)
    • 字段 − 也就是属性,可包含0到多个
    • 构造函数 − constructor,可包含0到1个
    • 方法 − 也就是行为动作,可包含0到多个

类的属性

class Name{

    // 字段

    age=10;

    name="Karen";

    // 方法

    say(){};

    // 构造函数

    constructor(n:number){

        this.age=n

    }

}

let n:Name=new Name(10)

类的方法

 类的方法参数和返回值都可声明类型,但都是可选的;

// 类型和方法

class Name1{

    // 字段

    age=10;

    name="Karen";

    // 方法

    say(n:number){

        return n*2

    };

    fn=(n1:number):any[]=>{

        return [n1,n1]

    };

    // 构造函数

    constructor(n:number){

        this.age=n

    }

}

let n1:Name1=new Name1(10)

n1.fn(100)

三、对象和内存

  1. new多次本质上是创建了多个了对象, 只有创建了对象,才能使用对象访问对象的字段或方法;
  2. 对象在堆中,计算机堆中内存无名字,只能通过地址使用之,堆中对象地址通过hash后得到引用值,引用类型变量保存的就是引用值;
  3. 每个对象都有唯一引用, 只能通过对象的引用使用对象, new 会返回对象的引用(this);
  4. 当类中定义了属性,该类的每个对象都会独立开辟出属性成员,当前对象独享;
  5. 创建对象时,方法不会被开辟出来,同一个类的方法被所有该类对象共用(原型和原型链);
  6. 同一对象可被多个变量引用,当一个对象没有引用时,对象的生命就被GC(拉圾回收机制)管理了, 当对象销毁时,对象中独享的字段成员也会随之销毁;
  7. 只有类不能做事情,类的对象才有用, 类成员(静态成员例外);

四、this

方法中可以使用this,该this引用调用方法的对象, 所以方法里可以使用 this.方法和this.字段访问实例成员;

五、构造函数

  1. 函数名为 constructor;
  2. 可带0到多个参数 (构造函数没有返值,也不用声明返回值类型);
  3. 实例化对象;
    3.1 构造函数无参时
     new 类名();
    3.2 构造函数有参时
    ​ new 类名(为构造函数传实参)
  4. 实例化过程(new 的过程发生了什么);
    ​ (1)在堆中实例化对象, 包括创建字段成员
    ​ (2)执行构造函数
    ​ (3)返回对象引用
  5. 构造函数存在的价值

​ (1)初始化一些操作并为对象属性赋值;

​ (2)构造函数中this值为新实例化的对象引用, 常通过"this.字段=值"为新对象的字段赋值;

六、静态方法

使用 static 修饰符修饰的方法称为静态方法,它们不需要实例化,而是直接通过类来调用:

// 静态方法

    class Animal{

        static begin(n:number){

            return n*2

        };

        fn=()=>{

            return ("函数调用了!")

        }

    }

    let a:Animal=new Animal()

    a.fn() //调用类中的函数

    a.begin(100) // 报错,只能使用类名来调用static

    Animal.begin(100)

 

 

    class Person2 {

        // 字段

        private age=10;

        protected doing="runing"

            name="Karen";

            // 方法

            fn=(n1:number):any[]=>{

                return [n1,n1]

            };

            private constructor(n:string){

                this.doing=n

                this.age=20

            }

            static sin(n:string){

                return new Person2(n)

            }

    }

    let m=Person2.sin("hello")

七、存取器

//存取器:用户提交的任何数据都是不可信的  CSRF

//使用 getter 和 setter 可以改变属性的赋值和读取行为,并且更安全(用户提交数据的时候提交的是攻击代码):

// 做一些自己想做的事情,比如数据发生改变的时候,重新渲染页面

        class Dog{

            birth:string

            get age(){

                // 取值

                return new Date().getFullYear()-new Date(this.birth).getFullYear()

            }

            set age( n:number){

                // 存值

                this.age=n

               

               

            }

            constructor(birth:string){

                this.birth=birth

            }

        }

        let dog1:Dog=new Dog("1999-11-13")

 

 

 

八、继承

  1. 语法
    classchild_class_nameextendsparent_class_name{ }
  2. 只能单继承(多继承会违背类本质), 一个类的父类只能有一个,但是一个类可以有多个子类。子类也可以再次被当作父类,形成树结构;
  3. 子类继承父类后,不会影响父类的独立使用;
  4. 类型上包含关系才能使用继承(同类事物才能使用继承, 如人是动物,所以人可以继承动物);
  5. 类中只能写本质的东西,如一个表示人的类,不能在类中写打乒乓球的方法,一个表示动物的类中不能写在水里游的方法。否则父类会侵略子类;
  6. 子类对象可以访问从直接和间接父类中继承下来的成员;
  7. 继承最原始的作用是什么?就是为了代码重用

class Cat{

    name:string="miumiu";

    age:number=5;

    run:boolean=true;

    fn=()=>{

        return this.run

    }

    constructor(n:string,n2:number,n3:boolean){

        this.name=n

        this.age=n2

        this.run=n3

    }

}

class Cat1 extends Cat{

    eat:string="正在吃饭"

}

let mao:Cat1=new Cat1("xiaoxiao",6,false)

mao.fn()

九、super

  1. 子类并且该子类带有构造方法,则该子类构造函数必须使用super(<实参>),不管父类是否写了构造方法;
  2. super要位于构造方法中的this使用之前;
  3. 子类对象的创建过程:创建父类对象,然后在父类对象基础上追加子类成员得到子类对象,然后子类构造函数先执行,子类构造函数中super(<实参>)再调用父类构造函数的执行 ;
  4. 没有继承父类,构造函数中就不能有super(<实参>);
  5. super(父类所需参数)
    如果父类和子类都有构造函数,并且父类构造函数有参数,那么要求子类构造函数 super(...)中必须为父类传参数。
  6. new 创建对象时,如果类中有构造方法,则以该构造方法所需参数传参
  7. new 对象时,如果类中无构造函数,并且该类又有父类,则以父类构造方法所需参数传参。(不提倡使用)
  8. 构造函数中的super还可以访问父类中继承下来的成员.(如果没有重写,不提倡使用)

实际上同一个类中super和this可以出现在构造函数和方法中,它们的值都是一样的,但是它们的偏移量不相同,super只管到父类对象,而this管到子类对象,而父类对象只是子类对象的一个组成部分。所以super只能访问父类的成员,而this可以访问父类和子类的成员

 

十、访问权限修饰符

修饰符分类

public:公用

private:私有

protected: 受保护

字段或方法的权限修饰符

private修饰的字段和方法只能在当前类中被使用

protected修饰的字段和方法只能在当前类及其子类中被使用

public 修饰的字段和方法在任何地方都可被使用,

(如果没有加权限修饰符,则默认为public)

// 修饰符分类

// public:公用    修饰的字段和方法在任何地方都可被使用,

// private:私有  修饰的字段和方法只能在当前类中被使用

    class Person {

        // 字段

        private age=10; //私有字段

            name="Karen";

            // 方法

            fn=(n1:number):any[]=>{

                return [n1,n1]

            };

            constructor(n:string){

                this.age=20

            }

    }

    class Student extends Person{

            say(n1:number){

                return n1*2

            }

    }

    let n2:Person=new Person("swiming")

    // console.log(n2.age)//报错,age只能在Person类中使用

// protected:  受保护    修饰的字段和方法只能在当前类及其子类中被使用

    class Person1 {

        // 字段

    private age=10;

    protected doing="runing"

        name="Karen";

        // 方法

        fn=(n1:number):any[]=>{

            return [n1,n1]

        };

        constructor(n:string){

            this.doing=n

            this.age=20

        }

    }

    class Student1 extends Person1{

        say(n1:number){

            return n1*2

        }

    }

    let n3:Person1=new Person1("flying")

// console.log(n3.doing) //报错,doing只能在Person类中使用

 

构造函数权限修饰符

private修饰构造函数,“new 类(...)” 只能在当前类的方法中进行, 构造函数为private的类不能当作父类

protected修饰构造函数, “new 类(...)” 只能在当前类及其子类中进行

public修饰构造函数, "new 类(...)" 任何地方可进行

访问修饰符与开闭原则

(1) 类中成员使用什么修饰符修饰,思想上必须符合开闭原则.

(2) 成员量写成私有,为成员变量提供get/set方法, 之所以这样做是因为函数安全性大于字段安全性

十二、重写

1 方法可以被重写。字段被重写无意义,不要做这种操作。

2 重写的语法:

​ 在父类和子类中, 两个方法名相同, 返回值类型相同, 参数相同, 子类重写方法时不能使用比父类中被重写的方法更加严格的修饰符

3 不能重写私有的方法

4 重写的思想

 所有子类都需要的方法,但是有些子类对方法不满意

5 使用子类对象访问有重写的方法时,父类方法会被隐藏,如果要访问父类中被重写的方法, 子类的构造函数或子类的方法中使用super来访问

6 实战中,super只有两种情况有实战意义

(1) 子类重写的方法里面使用super调用父类中被重写的方法

(2) 子类构造函数使用super调用父类构造函数

十三、里氏替换原则

​ 里氏替换原则通俗的来讲就是:子类可以扩展父类的功能,但不能改变父类原有的功能。里氏代换原则告诉我们,在软件中将一个基类对象替换成它的子类对象,程序将不会产生任何错误和异常,反过来则不成立,如果一个软件实体使用的是一个子类对象的话,那么它不一定能够使用基类对象。里氏代换原则是实现开闭原则的重要方式之一,由于使用基类对象的地方都可以使用子类对象,因此在程序中尽量使用基类类型来对对象进行定义,而在运行时再确定其子类类型,用子类对象来替换父类对象。里氏替换原则指导下要求父类的私有的成员,也必须有公用的方法间接你传递给子类。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值