js之继承

js之继承

js继承有许多继承,我们在这里就简述几个常用、实用、易理解的ES5继承。
JS中的类和实例是基于原型和原型链机制来处理的.

1.原型链继承

特点:

  1. JS继承也不像其他语言中的继承一样(其他语言:子类继承父类,就是拷贝一份父类的属性和方法),js中他是把父类的实例放到子类的原型链上,子类实例想要去调用这些属性和方法的时候,实际上是基于__proto__原型链查找的形式去完成的。
  2. 子类实例可以直接修改父类上的方法(这样就会导致其他父类实例都会收到影响)。
  3. 父类中私有的属性和方法,在实现原型链继承之后都会变成子类公有的属性和方法。
Child.prototype = new Parent();//让子类的原型指向父类的实例;
Child.prototype.constructor = Child;//为了保证原型链的完整性

具体实例:

 //父类实例:
    function A(x) {
        this.x = x//父类私有属性
    }
    A.prototype.getX = function () { //父类公有属性
        console.log(this.x);
    }

    //子类实例:
    function B(y) {  //子类私有属性
        this.y = y
    }
    B.prototype = new A(100);//使子类的原型指向父类的实例;
    B.prototype.constructor = B;//保证原型链完整
    B.prototype.getY = function () {//子类公有属性
        console.log(this.y);
    }

    let b = new B(200);
    b.x //==> undefined
    b.getX(); //==> b.getX is not a function

    console.log(a);//{x:100} ==> __proto__.getX =fn
    console.log(b);//{y:200} ==> __proto__.getY =fn

原型链继承
在这里插入图片描述

2.构造函数(使用call方法实现继承)

特点:

1.只能继承父类私有的属性和方法(因为只是把父类构造函数当作普通函数执行了一次,跟父类的原型上的方法和属性没有任何关系)。
2.父类的私有的属性和方法 都会变成子类私有的属性和方法。

// /call继承(借用构造函数继承)
        // //在子类构造函数中把父类构造函数当作普通的函数执行, 
        // 并且通过call方法把父类构造函数中的this替换成子类的实例(this), 
        // 这样相当于给子类实例设置了私有的属性和方法
        // 父类实例
        function A(x) {
            this.x = '哈哈哈'
        }
        A.prototype.get = function () {
            return 'abcd'
        }
        let a=new A(666)
        console.log(a);

        // 子类实例
        function B(x,y) {
            this.y = '嘻嘻嘻'
            A.call(this,y)
            
        }
        B.prototype.geta = function () {
            return 'EFGH'
        }
        let b=new B(666)
        console.log(b);
        console.log(b.x);
        console.log(b.get);//call继承子类只能拿到父类私有属性,父类公有属性拿不到

在这里插入图片描述

3.组合继承(结合原型链继承和借用构造函数继承的方法)

特点:
1.子类实例可以使用父类的私有属性和方法。
2.父类私有的属性和方法也会变成子类实例私有的属性和方法。
3.子类实例继承父类公有的属性和方法。
4.子类的原型链上会存在一份多余的父类私有属性。
函数可以复用不存在引用属性问题。

//父类构造函数
function Parent(x){
    this.x = x;
    this.sayHello = function (){
        console.log("sayHello")
    }
}
//父类原型
Parent.prototype.getX = function (){
    console.log("getX",this.x)
}

//子类构造函数
function Child(y,x){
    Parent.call(this,666)
    this.y = y;
}
Child.prototype = new Parent(100);
Child.prototype.constructor = Child;
Child.prototype.getY = function (){
    console.log("getY",this.y)
}
//子类实例
let c1 = new Child(200,666);

在这里插入图片描述

4.寄生组合继承(object.create)

结合原型链继承和借用构造函数继承的方法,同时需要自己创建prototype,实现寄生组合式继承
特点:

1.最完美的JS继承解决方案。
2.父类私有的属性和方法,子类实例私有的属性和方法。
3.父类公有的属性和方法,子类实例公有的属性和方法。
4.子类实例修改公有的属性和方法不会影响父类的实例。

//父类构造函数
function Parent(x){
    this.x = x;
    this.sayHello = function (){
        console.log("sayHello")
    }
}
//父类原型
Parent.prototype.getX = function (){//父类共有属性
    console.log("getX",this.x)
}
let p1 = new Parent(100);

//子类构造函数
function Child(y,x){
    Parent.call(this,666)
    this.y = y;
}
// Child.prototype = new Parent(100);//子类共有属性
// Child.prototype = {};

Child.prototype = Object.create(Parent.prototype);
Child.prototype.constructor = Child;
Child.prototype.getY = function (){
    console.log("getY",this.y)
}
//子类实例
let c1 = new Child(200,666);

// Object.create(arg)  创建一个空的对象,并且让这个空对象的__proto__指向传递的第一个参数

Object.create = function(obj){
//IE浏览器不支持用户在JS代码中直接的修改或者使用__proto__
    // let newObj = {};
    // newObj.__proto__ = obj;
    // return newObj

    function NewObj(){}
    NewObj.prototype = obj;
    return new NewObj()
}

在这里插入图片描述

ES6中的类之继承

class 相当于es5中构造函数,定义方法时,前后不能加function,全部定义在class的protopyte属性中
class和方法内默认都是严格模式,class中定义的所有方法是不可枚举的,只能定义方法,不能定义对象,变量等
es5中constructor为隐式属性

// ES5中的类(class) => 构造函数(constructor)
 function Parent(x){
     this.x = x;
     this.sayHello = function (){
         console.log("sayHello")
     }
 }
 Parent.prototype.sx= "属性";
 Parent.prototype.getX= function (){
     console.log("getX==>",this.x)
 }
 let p1 = new Parent(100);


{//ES6中的类
    class Parent {
        constructor(x) {
            this.x = x;
            this.sayHello = function () {
                console.log("sayHello")
            }
        }

        // sx: "属性",
        getX() {
            console.log("getX==>", this.x)
        }
    }

//公有属性
    Parent.prototype.name = "Parent";
//公有方法
 Parent.prototype.getX= function (){
     console.log("getX==>",this.x)
 }

    let p1 = new Parent(100)
}


//ES6中的继承

  class Parent {
        constructor(x) {
            this.x = x;
            this.sayHello = function () {
                console.log("sayHello")
            }
        }
        getX() {
            console.log("getX==>", this.x)
        }
    }

    class Child {
        constructor(y) {
            //在ES6的class没有办法直接当作一个普通函数执行
            // Child(123) //Uncaught TypeError: Class constructor Child cannot be invoked          without 'new' //必须使用new关键字来创建实例,不能当作一个普通函数执行
            // Parent.call(this,100)
            this.y = y;
        }
        getY(){
            console.log("getY==>", this.y)
        }
    }
    //在使用ES6的继承的时候,没有办法直接重定向子类的原型
   Child.prototype = Object.create(Parent.prototype);
    let c1 = new Child(200);

//ES6中的继承
//通过extends来实现的继承
//ES6继承 ==>class 子类构造函数 extends 父类构造函数{}
//Child.prototype.__proto__ = Parent.prototype;
/*
* 1. 父类的私有属性和方法,会成为子类的私有属性和方法
* 2.
* */
class Parent {
    constructor(x) {
        this.x = x;
        this.sayHello = function () {
            console.log("sayHello")
        }
    }
    getX() {
        console.log("getX==>", this.x)
    }
}
class Child extends Parent {
    //如果不写constructor,不会报错,继承会正常继承
    //如果不写constructor浏览器会自动的帮我们去创建以下代码
    // constructor(...args){
    //      super(...args)
    // }
    constructor(y) {
        super(100);// Parent.call(this,100)
        //Uncaught ReferenceError: Must call super constructor in derived class before accessing 'this' or returning from derived constructor
        //如果是通过继承的形式写了constructor,那么就必须使用super来继承父类的私有属性和方法,不然就会报错
        this.y = y;
    }
    getY(){
        console.log("getY==>", this.y)
    }
}
let c1 = new Child(200)

谢谢各位大佬的光临,请多多指教

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值