• 传统方法过渡到ES6去优雅地实现JavaScript的继承


          众所周知,面向对象编程有三个重要的概念: 封装、继承、多态。而JS作为面向对象的弱类型语言,应该说是基于对象的语言,正如常说的,JS的世界里,万物皆对象。虽然JS本身不是面向对象的语言,我们可以通过模拟的方法,来实现类似JAVA式的类继承,之后使用Es6语法,使我们更加简单方便的实现类的继承。

    1、创建一个自定义对象

    //构造函数
    function People(name,age){
        this.name = name;
        this.age = age;
    }
    //定义原型对象
    People.peototype={
        getName : function(){
            return this.name;
        },
        getAge : function(){
            return this.age;
        }
    }

    var p1 = new People('leaf',10);
    console.log(p1.getName()) //leaf

    2、当执行 var p1 = new People('leaf',10);内部主要做了这几件事   

         1. 创建新的空对象(new Object());

         2. 设置新对象的__proto__继承构造函数的prototype (p1.__proto__===People.prototype );            

         3. 将这个对象通过this关键字传递到构造函数中并执行构造函数。

         4. 将这个对象赋值给p1.

         实现一个new的方法: 

    function create() {
      // 创建一个空对象
      let obj = new Object();
      //获取构造函数
      let Constructor = [].shift.call(arguments)
      //连接到原型
      obj.__proto_ = Constructor.prototype;
      //绑定this
      let result = Constructor.apply(obj, arguments)
      //返回新对象
      return typeof result === 'object' ? result : obj;
    }
    
    function People(name, age) {
      this.name = name;
      this.age = age;
    }
    let p1 = create(People, 'leaf', 10);//调用自定义create实现new
    console.log(p1.name) //leaf
    console.log(p1.age) //10
    

      

    3、简单的继承,看看

    创建student类,它从People继承了原型prototype中所有的属性。

    function Student(name, age, score) {
        this.name = name;
        this.age = age;
        this.score = score;
    }
    将Studen原型指向Person的一个实例(其实就是Student.prototype里的__proto__指向了People的实例中的__proto__,
    而People的实例中的__proto__又指向了People.prototype)。
    因为People的实例可以调用People原型中的方法, 所以Studen的实例也可以调用Person原型中的所有属性。
    Studen.prototype = new Person(); Student.prototype.constructor = Student; //避免实例的constructor属性指向Object函数 Studen.prototype.getScore= function() { return this.score; };
    var p1 = new Employee("leaf", "12", "100"); console.log(p1.getName()); // "leaf  

      

    4、三种的方法存在的问题

       1、在创建Student构造函数和原型时,就对Pelple进行了实例化,这是不合适的。
       2、Student的构造函数没法调用父类Person的构造函数,导致在People构造函数中对name和age属性的重复赋值。
       3、Student中的函数会覆盖Pelple中的同名函数,没有重载的机制.

    5、修复之后更加优雅地继承

    //构造函数
    function People(name,age){
        this.name = name;
        this.age = age;
    }
    //定义原型对象
    People.prototype={
        constructor : People,
        getName : function(){
            return this.name;
        },
        getAge : function(){
            return this.age;
        }
    }
    
    //定义一个Student类
    function Student(name,age,score){
        //调用Peopel构造函数,this指向了People
        People.apply(this,arguments);
        this.score=score;
    }
    
    Student.prototype = {
        constructor :Student,
        getScore:function(){
           return this.score;
        }
    }
    
    让Student的原型对象继承People的原型对象
    Object.setPrototypeOf(
        Student.prototype, People.prototype
    );
    
    var p2 = new Student('kafu',10,99);
    console.log(p2.getScore());//99
    console.log(p2.getName()); //kafu
    console.log(Student.prototype.constructor==Student); //true
    

     

    setPrototypeOf的polyfill
    Object.setPrototypeOf = Object.setPrototypeOf || function(obj, proto) {
      obj.__proto__ = proto;
      return obj; 
    }
    

      

     

    6、传统方法小结

    主要利用两点

    1、在子类型构造函数中调用父类型构造函数,改变this的指向。

    注意:可以使用call(this,参数属性)、apply(this,[参数数组])

    2、利用Object.setPrototypeOf()
    注意:该方法的Polyfill

    Object.setPrototypeOf = Object.setPrototypeOf || function(obj, proto) {
      obj.__proto__ = proto;
      return obj; 
    }
    

      

    7、ES6实现类的继承

    //定义People类
    class People{
        //构造函数
        constructor(name,age){
            this.name = name;
            this.age = age;
        }
    
        //原型上的方法
        getName(){ //没有function哦
            return this.name;
        }
        
        getAge(){
            return this.age;
        }   
    }
    //创建Student类并去继承People类
    class Student extends People{
        constructor(name, age, score){
            super(name, age); //调用父类型的构造方法
            this.score = score;
        }
    
        getScore(){
           return this.name+'的成绩是:'+this.score;
        }
    
    }
    
    //usage
    var p3 = new Student('kafu',10, 99);
    console.log(p3.getScore());
    

      

    8、es6方法的总结

      1、es6中的extends其实就像传统方法中的

       Object.setPrototypeOf(
          Student.prototype, People.prototype
      );

      让子元素的原型继承父元素的原型

      2、es6中的super()其实就像传统方法中 People.apply(this,arguments);借用父类中的构造函数。

      3、可见深刻理解传统方法之后,对掌握好es6的新语法是有很大的帮助的。

  • 相关阅读:
    两类斯特林数的整理
    SXOI2019游记
    3.13校内测试
    Python Flask 实现移动端应用接口(API)
    CentOS下实现Flask + Virtualenv + uWSGI + Nginx部署
    iOS组件化开发入门 —— 提交自己的私有库
    Runtime ----- 带你上道
    iOS核心动画以及UIView动画的介绍
    GCD中各种队列和任务执行方式的组合
    iOS消息转发机制和使用
  • 原文地址:https://www.cnblogs.com/leaf930814/p/6921924.html
Copyright © 2020-2023  润新知