js中的类(ES5/6)

首先,类的继承分为es5方法和es6方法。

ES5(涉及到原型链)

  1. ES5中的类用构造函数实现。

    function Animal(name){
        this.name=name
    }
    Animal.prototype.eat='胡萝卜'
    let rabbit = new Animal('小兔子')
    
    console.log(rabbit.hasOwnProprity(name)) //①true
    console.log(rabbit.hasOwnProprity(eat))  //②false
    console.log(rabbit.eat) //胡萝卜
    

    其中,Animal就是构造函数,通过new构造了一个实例对象rabbit。
    在构造函数中通过this定义的属性或者方法都会实例化到每一个对象中,作为每一个对象自身的属性和方法,这就是①处true的原因;在构造函数原型上定义的属性或方法是公共的,实例对象可以调用但是不是本身的这就是②处false的原因。
    一个对象,可以使用自己本身的属性和方法,也可以使用其原型链上的属性和方法。
    还有两个重要的关系:
    animal._proto===Animal.prototype
    Animal.prototype.constructor===Animal

  2. 定义抽象类以及类的继承关系

    • 构造函数方法(在子类的构造函数中实例化父类)
    function Animal(){
        if(new.target==Animal)
        throe new ERROR('这是一个抽象类,不能直接new实例化S!只能被继承!')
        this.type='动物'
    }
    function Rabbit(food){
        //继承父类实例的属性和方法,可以传参的
        Animal.call(this)
        //子类自己的属性
        this.food=food
    }
    

    缺点: 无法继承父类原型中的属性和方法

    • 原型链继承
    function Father(){
    this.name = '张三'
    }
    // 父类的原型方法
    Father.prototype.getName = function(){
        console.log(this.name)
    }; 
    function Son(){};
    //让子类的原型对象指向父类实例
    Son.prototype = new Father();
    //根据原型链的规则,绑定一下constructor(否则constructor指向的是Father), 这一步不影响继承, 只是在用到constructor时会需要
    //一开始Son.prototype身上是没有constructor的,需要根据原型链找到Father.prototype,constructor是Father;于是可以直接给Son.prototype添加constructor
    Son.prototype.constructor = Son;
    

    缺点: 修改一个子类实例的父类中的引用类型,所有子类实例的父类中的引用类型都会修改
    原因: 修改子类实例中的父类基本类型时,直接在子类实例上添加了一个同名属性,是属于该实例自己的,不影响其他实例。引用类型保存的都是指针,sub1和sub2指针不同但是指向同一地址。现在把地址里的内容改了,所以两者都有变化

    • 组合式继承。
    function Animal(){
        if(new.target==Animal)
        throe new ERROR('这是一个抽象类,不能直接new实例化S!只能被继承!')
        this.type='动物'
    }
    function Rabbit(food){
        //继承父类实例的属性和方法
        Animal.call(this)
        //子类自己的属性
        this.food=food
    }
    //继承父类原型上的属性和方法
    Tiger.prototype=new Animal()
    
    • 寄生式组合继承
    function Father(){
    this.name = '张三'
    }
    // 父类的原型方法
    Father.prototype.getName = function(){
        console.log(this.name)
    }; 
    function Son(){
        Father.call(this)
    };
    //Object.create(proto)这个函数的作用是创建一个对象,这个对象的__proto__是传入的参数
    //即Son.prototype.__proto__=Father.prototype
    Son.prototype = Object.create(Father.prototype) 
    

    关于最后为什么不写Tiger.prototype = Animal.prototype
    如果这么写,二者的原型是同一个对象(浅拷贝),父类的方法子类确实可以得到,但是如果在子类原型上添加方法,同样会影响到父类,这是不符合继承特点的。现在这么写,对Tiger.prototype的操作并不会影响Animal.prototype,同时可以使Tiger.prototype可以循着原型链找到Animal.prototype的属性方法。

ES6

// class不存在变量提升,所以一定要先声明再实例化
class Classname{
    // 每次new的时候就会触发
    constructor(arg1,arg2){
        this.arg1=arg1;
        this.arg2=arg2;
        //……
    }
    //方法 ,直接写,不需要function声明
    show(){

    }
    //static关键字(静态方法)
    // 静态函数的调用者是类本身,不是实例,也就是说this指向这个类
    // 所以静态函数之间是可以用this互相调用的
    static myselfFunction(){
        // 这是一个静态函数
    }
    //用的时候要注意tag是实例的属性,不是函数,不要加()
    set tag(newarg1){
        this.arg1=newarg1
    }
    
    get tag(){
        return this.arg1
    }
}
class Son extends Classname{
    constructor(arg1,arg2,arg3){
        //如果直接写就会直接覆盖父类的constructor
        //由于extends继承,this会混乱,因此一定要super后才能使用this
        super(arg1,arg2)
        this.arg3=arg3
    }
    //写独有方法或重写父类方法
}
let test = new Classname(arg1,arg2);
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值