class类

说明:

class就是构造函数的语法糖,在使用继承的时候会更加方便,并且在思想上和java等统一起来

class Man {
  // ...
}

typeof Man // "function"
Man === Man.prototype.constructor // true

一、创建类

class的属性、方法

作用:

批量创建对象,功能和构造函数相似,只是写法不同

场景:

插件、复用的功能、vue(每一个组件都是一个实例)、js动画(批量创建小球实例,每一个小球都有自己的运动轨迹)

class Man {
    // 构造器
    // 设置实例属性,内容都是非共享的原型(非共享)
    constructor(name,age){
        this.name = name;
        this.age = age;
        this.sex = '男'
        this.car = {
            car1:'奔驰',
            car2:'宝马',
            car3:'奥迪'
        }
        this.eat = function(){}
    }
    // 设置原型方法,内容都是共享的原型(共享)
    smoking(){}
    play(){}
}
// 和构造函数一样,通过new关键字调用
let yj1 = new Man('yj1',18) 
let yj2 = new Man('yj2',18)
// {
//    age: 18, 
//    name: "yj2",
//    sex: "男",
//	  this.car:{...省略}
//    eat(){} ,
//    prototype: {smoking(){}, play(){}}
// }
yj1.car === yj2.car // false 实例本身的方法(非共享)
yj1.eat === yj2.eat // false 实例本身的方法(非共享)
yj1.smoking === yj2.smoking // true 实例原型身上的方法(共享)

注意:

  1. constructor会默认存在,并调用

  2. constructor写入的都是实例属性和方法,属于非共享内容

  3. constructor同级写入的都是原型方法,属于共享内容

class的属性新写

作用:

简化代码,没有功能优化,只是让书写属性时更加方便、简洁(少写了this,将属性从constructor释放出来)

class Man {
    sex = '男'
	height = 180
	_height = 180
    constructor(name,age){
        this.name = name;
        this.age = age;
    }
	smoking(){}
    play(){}
}
// 和构造函数一样,通过new关键字调用
let yj1 = new Man('yj1',18) 
// {
//    age: 18, 
//    name: "yj1",
//    sex: "男",
//	  height = 180,
//    _height = 180,
//    prototype: {smoking(){}, play(){}}
// }

注意:

  1. 实例属性新写法,程序员一般喜欢写在constructor顶部
  2. 实例属性新写法,程序员一般在前面加下划线

class的静态属性、方法

作用:

调用方便,直接在类身上调用属性和方法,不需要通过new出实例才可使用(实例对象无法调用属性和方法),比如:Date.now()

定义:

在普通属性和方法前面加入 static 即可,使用时不需要携带static

class Man {
    _sex = '男'
    static _age = 18
	constructor(){}
    static smoking(){
        console.log(this.age)
        this.play()
    }
	static play(){}
}
Man._age // 18
Man.smoking() // 先调抽烟,再掉玩的方法

注意:

  1. 静态方法里面的this指向class本身,不指向实例对象
  2. 静态方法在调用时,里面可以使用静态属性和静态方法,但不允许调用实例方法和实例属性
  3. 静态属性可以使用,但暂未列入语法规则中

class的私有属性、方法

作用:

提供一些只能自己调用的属性和方法,防止被外部篡改(只允许类在内部自己调用,实例无法调用)

定义:

在普通属性和方法前面加入# 号即可,#属于私有属性、方法的一部分,所以调用也需要加入#号

class Man {
    #sex = '男'
    constructor(){
        
    }
	init(){
        this.#smoking()
        this.#play()
        console.log(this.#sex)
    }
    #smoking(){}
	#play(){}
}
let yj = new Man()
yj.init() // 先抽烟再玩、再打印男属性
yj.#sex  //报错
yj.#smoking() //报错

class的get和set方法

作用:

自定义get和set的方法

类似于数据劫持Object.definedProperty(),获取和设置的时候都会触发对应get和set方法

class Man {
    #_age = 18
    constructor(name,age){
        this.name = name;
    }
	get age(){
        console.log('获取属性');
        return this.#_age
    }
    set age(v){
        console.log('设置属性');
        this.#_age = v
    }
}
// 和构造函数一样,通过new关键字调用
let yj = new Man('yj') 
console.log(yj.age) // 打印:获取属性 18
yj.age = 19  // 打印:设置属性
console.log(yj.age) // 打印:获取属性 19
场景:

一些框架中的私有数据,在class中定义了使用了私有数据后,不方便直接对外暴露(可以修改,但不允许随意修改,所以要提供一些固定方法),可以通过get和set代理

注意:

  1. 调用get、set时,千万别直接获取、赋值给自己,会导致递归死循环(get/set触发设置,又会重新触发新的get/set)

二、继承类

class的继承

作用:

让功能更加强大、站在巨人的肩膀上开发

使用function也可以实现继承,并且方法很多,但是都是非常麻烦

而class类可以非常清晰和方便的解决这个问题

子类和父类名字一样(重写父类,采用就近原则)

场景:

给轮播图插件新增几个功能、在IT的基础类上功能变成前端类

class Father {
    constructor(name,money){
        this.name = name
        this.money = money
    }
    makeMoney(){
    	console.log(this.name+'赚钱');
    }
}
class Son extends Father{
    constructor(name,money,toy){
        super(name,money)
        this.toy = toy
    }
    study(){
    	console.log(this.name+'学习');
    }
}
let son = new Son('son',100,'变形金刚')
let fa = new Father('father',1000)
son.makeMoney() // son赚钱
son.study() // son学习
fa.makeMoney() // fa赚钱
fa.study() // 报错  子继承父,所有子有父的方法、父没有子的方法

注意:

  1. 实现继承时,constructor中必须第一时间执行super(),super()相当于先创造父类,先有父再有子(Es5和es6的继承思路不一样)

    1. Es5 先创建子实例,再把父方法和属性继承到子实例上
    2. Es6 先把父方法和属性放到子类中,再创建子实例
  2. 父子存在相同的属性或者方法时,优先使用自己的属性和方法

  3. 静态属性和方法可以继承的(子类可以直接调用父类的属性和方法)

  4. 私有属性和方法是无法继承的(子类中无法调用父类的私有属性和方法,但可以调用父类的普通方法,间接调用父类的私有属性和方法)

  5. super当作函数调用时指向父类(存在继承时调用super(),相当于把父类执行一遍),但返回子类实例

  6. super当做对象使用时指向父级原型,但this指向子类实例对象(把父级方法拿过来,让儿子调用)

    // 在普通函数中把super当对象使用,super相当于在父级的原型上调用
    class F {
        constructor() {
            this.fn1 = function () {
                console.log('父级实例方法');
            }
        }
        fn2() {
            console.log('父级原型方法');
        }
    }
    class S extends F {
        constructor() {
            super()
            
            super.fn1() // 报错(实例方法)
            super.fn2() // 父级原型方法(原型方法)
        }
    }
    new S()
    
    // 在静态函数中把super当对象使用,super相当于在父类
    class F {
        constructor() {}
        static fn() {
            console.log('父类静态方法');
        }
        fn(){
            console.log('父类实例方法');
        }
    }
    class S extends F {
        constructor() {
            super()
        }
    }
    S.fn() // 父类静态方法-----子类调静态方法会直接找父级调静态方法
    
    // 在静态函数中把super当对象使用,super相当于在父类
    class F {
        constructor() {}
        static fn() {
            console.log('父类静态方法');
        }
        fn(){
            console.log('父类实例方法');
        }
    }
    class S extends F {
        constructor() {
            super()
            super.fn()
        }
    }
    new S() // 父类实例方法----子级new的是实例,调的也是实例方法
    
  7. 子级中只能把super当对象和函数使用,无法单独打印或使用变量 super

三、class和ts结合

class的abstract(ts的抽象类、抽象方法)

作用:

抽象类,只能用于继承,不能单独实例化(ts内容)

抽象方法,子类在继承的时候,必须重写(ts内容)

定义:

在普通class前面加上abstract

abstract class Person {
    abstract sayHei():void // 这个抽象类,只能被继承,不能被实例化
}
let p = new Person() // 不允许,只能被继承
class Man extends Person{
    sayHei(){} // 必须重写父类的方法,否则ts报错
} // 允许,可以被继承

class的修饰符

作用:

public 公共属性(默认值),属性可以在任意位置访问和修改

private 私有属性,属性只可以在class内部访问和修改–一般在类中添加方法,使得私有属性可以被外部访问和修改

protected 受包含属性,只能在当前class和子class中访问和修改,实例无法访问

定义:

在属性前面加上public 、private 、protected

class P {
    private _name: string
    public _age: number
    protected _sex: number 
    constructor(_name:string,_age:number) { 
        this._name = _name
        this._age = _age
    }
	go1(){
        this.
    }
}
let yj = new P('yj',99)
yj._name = 'zd2' // ts报错,提示,私有的_name属性无法控制
yj._age = 999    // ts不报错,公共属性可以修改
console.log(yj);

class P {
    private name: string
    public age: number
    protected sex: number
    constructor(name: string, age: number, sex: number) {
        this.name = name
        this.age = age
        this.sex = sex
    }
    changeSex() {
        this.sex = 999
    }
}
class PPPP extends P { 
    changeSex() { 
        this.sex = 999
    }
}

let yj = new P('yj',9,0)
let yjj = new PPPP('yj',9,0)
yj.name = 'yjj' // ts报错,提示,属性name是私有的,只能在当前类中修改
yj.age = 99
yj.sex = 1 // ts报错,提示,属性sex受到保护,只能在当前类和子类中修改
yj.changeSex()  
yjj.changeSex()

注意,不可以在interface实现(implements)的时候写私有private

interface Person {
    _name?: string //报错,接口不允许出现私有
}
class P implements Person {
    private _name: string
}
Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐