JS继承

作者: 苹果咏 | 来源:发表于2019-07-11 17:57 被阅读0次

    1、prototype继承
    prototype对象包含所有实例对象需要共享的属性和方法,那些不需要共享的属性和方法就放在构造函数里。
    实例对象一旦创建,将自动引用prototype对象的属性和方法。
    以dog构造函数举例:

    function dog(name){
      this.name = name;
    }
    dog.prototype = { species:'狗' };
    var dogA = new dog('小黑');
    var dogB = new dog('小黄');
    
    alert(dogA.species); // 狗
    alert(dogB.species); // 狗
    

    优点:
    父类的方法得到了复用。

    缺点:
    原型中属性的改变会反应到所有的实例上
    创建子类的实例时,不能向父类的构造函数传递参数

    2、使用 class 语法糖继承

    class Person{
      constructor(name, sex){
        this.name = name;
        this.sex = sex;
      }
    }
    
    class Man extends Person{
      constructor(name){
        super('','male');
        this.name = name;
      }
    }
    
    let Lee = new Man('Lee')
    console.log(Lee.name, Lee.sex) // Lee male
    

    3、利用父构造函数继承属性

    function Father(uname, age){
        this.uname = uname;//这里this指向父构造函数
        this.age = age
    }
    function Son(uname, age,score,job){
        Father.call(this, uname, age)//调用父构造函数,这里的this一定要写在第一个,而且可以表示多个参数
            this.score = score//自己的属性
            this.job= job
    }
    var son = new Son('李丽',18,100,'学生')
    console.log(son)//Son {uname: "李丽", age: 18,score:100,job:"学生"}
    

    4、利用原型对象继承方法

    // 借用父构造函数继承属性
            // 1. 父构造函数
            function Father(uname, age) {
                // this 指向父构造函数的对象实例
                this.uname = uname;
                this.age = age;
            }
            Father.prototype.money = function() {
                console.log(100000);
    
            };
            // 2 .子构造函数 
            function Son(uname, age, score) {
                // this 指向子构造函数的对象实例
                Father.call(this, uname, age);
                this.score = score;
            }
            // Son.prototype = Father.prototype;  这样直接赋值会有问题,如果修改了子原型对象,父原型对象也会跟着一起变化
            Son.prototype = new Father();
            // 如果利用对象的形式修改了原型对象,别忘了利用constructor 指回原来的构造函数
            Son.prototype.constructor = Son;
            // 这个是子构造函数专门的方法
            Son.prototype.exam = function() {
                console.log('孩子要考试');
    
            }
            var son = new Son('刘德华', 18, 100);
            console.log(son);
            console.log(Father.prototype);
            console.log(Son.prototype.constructor);
    

    5、ES6继承

    class Calculator {
            constructor(a,b){
                this.a = a;
                this.b = b;
            }
            add(a,b){
                return ("相加結果:"+ (a+b))
            }
        }
        class Son extends Calculator{
            add(a,b){
                console.log(super.add(a,b))
            }
        }
        var rt = new Son()
        rt.add(3, 4)
    

    super.add(a,b)就是调用父类中的普通函数


    继承中属性和方法的查找原则是就近原则:

    class Calculator {
            add(){
                console.log ("我是父親")
            }
        }
        class Son extends Calculator{
            add(){
                console.log ("我是兒子")
            }
        }
        var son = new Son()
        son.add()//我是兒子
    



    子类扩展函数,并调用父类的构造函数:

    class Calculator {
            constructor(a,b){//構造函數
                this.a = a;
                this.b = b;
            }
            add(a,b){//普通函數
                console.log ("相加結果:"+ (a+b))
            }
        }
        class Son extends Calculator{
            constructor(a,b,c){
                //利用super調用父類構造函數,super必須在this之前,爹是最大的
                this.c = c //ReferenceError
                super(a,b)
                this.c = c // 正确
            }
            reduce(a,b,c){
                console.log ("相減結果:"+ (a-b-c))
            }
        }
        var rt = new Son()
        rt.add(3, 4)
        rt.reduce(3, 4)
    



    this指向问题,谁调用,this就指向谁:

    var _that
        class Calculator {
            constructor(a,b){//构造函数
                _that = this//将constructor的this给that
                this.a = a;
                this.b = b;
                document.querySelector('button').onclick = this.add
            }
            add(){
                //这里的this指向的是button按钮,谁调用,this就指向谁
                //我们要的值是存在constructor中,所以用that将constructor弄过来
                console.log(this)
                console.log ("相加結果:"+ (_that.a+_that.b))
            }
        } 
        var rt = new Calculator(3,4)
    
    image.png

    ES6原型问题总结

    //类的 prototype 属性和__proto__属性
    class A {
    }
    
    class B extends A {
    }
    
    B.__proto__ === A // true   子类的__proto__属性,表示构造函数的继承,总是指向父类。
    B.prototype.__proto__ === A.prototype // true   子类prototype属性的__proto__属性,表示方法的继承,总是指向父类的prototype属性。
    
    
    //实例的 __proto__ 属性
    //子类实例的__proto__属性的__proto__属性,指向父类实例的__proto__属性。也就是说,子类的原型的原型,是父类的原型。
    var p1 = new A();
    var p2 = new B();
    
    p2.__proto__ === p1.__proto__ // false
    p2.__proto__.__proto__ === p1.__proto__ // true
    

    总结:
    ES5中:
    利用借用构造函数实现实例属性和方法的继承 ;
    利用原型链或者寄生式继承实现 共享的原型属性和方法的继承 。

    ES6中:
    利用class定义类,extends实现类的继承;
    子类constructor里调用super()(父类构造函数)实现 实例属性和方法的继承;
    子类原型继承父类原型,实现原型对象上方法的继承。

    相关文章

      网友评论

          本文标题:JS继承

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