• js继承


    什么是继承?

      A对象通过继承B对象,就可以拥有B对象的所有属性和方法。

    原型链继承:

      子类的原型是父类的实例,子类继承父类的所有私有属性、私有方法和其原型上的属性和方法。

            // 定义父类Person
            function Person(name,age){
                this.name=name;
                this.age=age;
                this.eat=function(){
                    console.log("Person的私有eat方法");
                };
            }
            Person.prototype.play=function(){
                console.log("Person的公有play方法");
            };
            Person.prototype.sex="男";
            // 定义子类Student
            function Student(score){
                this.score=score;
                this.eat1=function(){
                    console.log("Student的私有eat1方法");
                };
            }
    
            // 子类继承父类
            Student.prototype=new Person("wql",23);    // 子类的原型是父类的实例  ----无法向父类构造函数传参
    
            Student.prototype.sex1="女";
            Student.prototype.play1=function(){
                console.log("Student的公有play1方法");
            };
    
            // 实例化子类
            var s1=new Student(100);
    
            console.log(s1.score)   // 100
            console.log(s1.sex1)    //
            s1.eat1()   // Student的私有eat1方法
            s1.play1()  // Student的公有play1方法
            console.log(s1.name)    // wql
            console.log(s1.age)     // 23
            console.log(s1.sex)     //
            s1.eat()    // Person的私有eat方法
            s1.play()   // Person的公有play方法

      缺点:

        1、无法实现多继承

        2、来自原型对象的所有属性被所有实例共享

        3、创建子类时,无法向父类构造函数传参

        4、要想为子类新增属性和方法,必须要在Student.prototype=new Person()之后执行,不能放到构造器中

    借用构造函数继承:

      在子类构造函数中通过call()调用父类构造函数。

            function Person(name,age){
                this.name=name;
                this.age=age;
                this.play=function(){
                    console.log("play")
                };
            }
            Person.prototype.eat=function(){
                console.log("eat")
            };
    
            function Student(name,age,score){
                Person.call(this,name,age);  // 调用父类构造,可以向父类传参
                this.score=score;
            }
            var s1=new Student("wql",23,100);
    
            console.log(s1)     // Student {name: "wql", age: 23, score: 100, play: ƒ}
            console.log(s1.score)   // 100
            console.log(s1.name)    // wql
            console.log(s1.age)     // 23
            s1.play()   // play
            s1.eat()    // 语法错误  ----仅调用构造函数的方法不能继承父类的原型上的属性和方法

      缺点:

        1、实例不是父类的实例,只是子类的实例

        2、只能继承父类的实例属性和方法,不能继承父类的原型上属性和方法

        3、无法实现函数复用,每个子类都有父类实例函数的副本,影响性能

    组合继承(原型链+借用构造函数):

      通过调用父类构造,继承父类的属性并保留传参的优点,然后把父类的实例作为子类的原型,实现函数复用。

            function Person(name,age){
                this.name=name;
                this.age=age;
                this.play=function(){
                    console.log("play")
                }
            }
            Person.prototype.eat=function(){
                console.log("eat")
            }
    
            function Student(name,age,price){
                Person.call(this,name,age); // 调用父类构造  ----好处是可以向父类传参
                this.price=price;
                this.setScore=function(){
                    console.log("setScore")
                }
            }
            Student.prototype=new Person(); // 父类的实例作为子类的原型
            Student.prototype.constructor=Student;  // 修复构造函数的指向
            Student.prototype.sayHello=function(){
                console.log("sayHello")
            }
            var s1=new Student("wql",23,100);
            var s2=new Student("syz",30,150);
    
            console.log(s1)     // Student {name: "wql", age: 23, price: 100, play: ƒ, setScore: ƒ}
            console.log(s2)     // Student {name: "syz", age: 30, price: 150, play: ƒ, setScore: ƒ}
            console.log(s1.name)     // wql
            console.log(s1.age)      // 23
            s1.play()     // play
            s1.eat()      // eat  ----父类的实例作为子类的原型,可以继承父类的原型属性和方法
            s1.setScore()     // setScore
            s1.sayHello()     // sayHello
            console.log(s1.constructor)     // 打印Student函数

      缺点:调用了两次父类构造函数,生成了两份实例。

      通过父类原型和子类原型指向同一个对象,子类可以继承父类的公有方法作为自己的公有方法,而且不会初始化两次实例方法/属性,避免了组合继承的缺点。

            function Person(name,age){
                this.name=name;
                this.age=age;
                this.play=function(){
                    console.log("play")
                }
            }
            Person.prototype.eat=function(){
                console.log("eat")
            }
            function Student(name,age,price){
                Person.call(this,name,age);
                this.price=price;
                this.setScore=function(){
                    console.log("setScore")
                }
            }
            Student.prototype=Person.prototype;  // 父类原型和子类原型指向同一个对象
            Student.prototype.sayHello=function(){
                console.log("sayHello")
            }
            var s1=new Student("wql",23,100);
            console.log(s1)     // Student {name: "wql", age: 23, price: 100, play: ƒ, setScore: ƒ}
            console.log(s1.name)     // wql
            console.log(s1.age)      // 23
            console.log(s1.price)    // 100
            s1.play()     // play
            s1.eat()      // eat
            s1.setScore()     // setScore
            s1.sayHello()     // sayHello

      缺点:无法确定实例是子类还是父类创造的,子类和父类的构造函数指向是同一个。

      原型可以基于已有的对象来创建对象,var B=Object.create(A);----以A对象为原型,生成B对象,B继承了A的所有属性和方法。

            function Person(name,age){
                this.name=name;
                this.age=age;
            }
            Person.prototype.eat=function(){
                console.log("eat")
            }
            function Student(name,age,price){
                Person.call(this,name,age);
                this.price=price;
                this.setScore=function(){
                    console.log("setScore")
                }
            }
            Student.prototype=Object.create(Person.prototype);  // 将Person的原型复制给Student的原型
            Student.prototype.constructor=Student;  // 修复构造函数的指向
    
            var s1=new Student("wql",23,100);
    
            console.log(s1)     // Student {name: "wql", age: 23, price: 100, setScore: ƒ}
            console.log(s1.name)    // wql
            console.log(s1.age)     // 23
            console.log(s1.price)   // 100
            s1.eat()    // eat
            s1.setScore()   // setScore
            console.log(s1 instanceof Student,s1 instanceof Person)     // true true
            console.log(s1.constructor)     // 打印Student函数

      几乎完美!

    ES6的class继承:

      通过extends关键字实现继承。

            // 定义父类
            class Person{
                constructor(name,age){
                    this.name=name;
                    this.age=age;
                    this.play=function(){
                        console.log("play")
                    }
                }
                showName(){
                    console.log("调用父类的方法")
                    console.log(this.name,this.age)
                }
            }
            let p1=new Person("wql",23);
            console.log(p1)     // Person {name: "wql", age: 23, play: ƒ}
    
            // 定义一个子类
            class Student extends Person{
                constructor(name,age,salary){
                    super(name,age);    // 通过super调用父类的构造方法,继承来自父类的name、age属性和play方法
                    this.salary=salary;
                }
                showName(){
                    console.log("调用子类的方法")
                    console.log(this.name,this.age,this.salary)
                }
            }
            let s1=new Student("syz",30,10000000);
            console.log(s1)     // Student {name: "syz", age: 30, salary: 10000000, play: ƒ}
            s1.showName()   // 调用子类的方法 syz 30 10000000
            s1.play()   // play

      Student通过extends关键字继承Person,在constructor中通过super()调用父类的构造方法。

  • 相关阅读:
    java里如何使用输入流和输出流实现读取本地文件里内容和写出到本地文件里
    Windows 命令行基础(博主推荐)
    Python2.7编程基础(博主推荐)
    27 个Jupyter Notebook的小提示与技巧
    java里如何实现循环打印出字符或字符数组里的内容
    [转]angularjs之ui-grid 使用详解
    [转]AngularJS 实现 Table的一些操作(示例大于实际)
    [转]js 回车转成TAB(利用tabindex)
    [转] Entity Framework添加记录时获取自增ID值
    [转]使用依赖关系注入在 ASP.NET Core 中编写干净代码
  • 原文地址:https://www.cnblogs.com/wuqilang/p/11937088.html
Copyright © 2020-2023  润新知