ES5和ES6的继承区别(class类)

ES5和ES6的继承区别(class类)

  • ES5继承

    • 寄生组合式继承(基本思想)

      • 定义祖先
      • 定义祖先可继承的变量
      • 定义继承的类(构造函数),并在类中调用组件的方法
      • 使用 prototyoe定义继承关系
      • 重新将constructor指向自己
      function (a){
          this.varA = a;
      }
      
      //定义祖先对象的可继承属性和方法
      A.prototype = {
          varA : null,
          doSomeThing: function(){
              console.log(this.varA);
          },
      }
      
      //定义继承函数
      function B(a,b){
          A.call(this,a);
          this.varB = b;
      }
      //定义继承关系
      B.prototype = Object.create(A.prototype)
      B.prototype.doSomeThing = function(){
          console.log(this.varB);
      }
      //绑定Constructor
      B.prototype.constructor = B;
      
      var b = new B('a','b');
      var a = new A('a');
      a.doSomeThing();
      b.doSomeThing();
      

请添加图片描述

  • ES6继承

    • 基本思想

      • Class之间通过使用extends关键字,这比通过修改原型链实现继承,要方便清晰很多
      class Colorpoint extends Point {
          constructor(x,y,color){
              super(x,y); //调用父类的constructor(x,y)
              this.color = color
          }
          toString(){
              //调用父类的方法
              return this.color + ' ' + super.toString();
          }
      }
      
    • 注意事项

      • 子类必须在constructor中调用super方法,否则新建实例时会报错,这是因为子类没有自己的this对象,而是继承父类的this对象,然后对其进行加工,如果不调用super方法,子类就得不到this对象,因此,只有调用super之后,才可以使用this关键字

请添加图片描述

  • 区别和不同

    • 类内部定义的方法,是不可枚举的,和ES5不同

    • 类不存在变量提升,这一点和ES5不同

    • 类相当于实例的原型,所有在类中定义的方法,都会被实例继承,如果在一个方法前,加上static关键字,就表示该方法不会被实例继承,而是直接通过类来调用,这就称之为静态方法

    • es5的继承,实质是先创造子类的实例对象this,然后再将父类的方法添加到this上面,es6的继承机制完全不同,实质先创造父类的实例对象this,所以必须先调用super方法`,然后再用子类的构造函数修改this

    • 类的prototype属性和proto属性,大多数浏览器的ES5实现之中,每一个对象都有proto属性,指向对应的构造函数的prototype属性,Class作为构造函数的语法糖,同时有prototype属性proto属性,因此同时存在两条继承链

      • 子类的proto属性,表示构造函数的继承,总是指向父类

      • 子类的prototype属性的proto属性,表示方法的继承,总是指向父类的prototype属性

        //类和模块的内部,默认就是严格模式,所以不需要使用use strict指定运行模式。
        //只要你的代码写在类或模块之中,就只有严格模式可用。
        class Point {
            //constructor方法,就是构造方法
            //如果没有定义constructor方法,JS会自动为其添加
            //constructor方法默认返回实例对象(即this),完全可以指定返回另外一个对象。
            constructor(x, y) {
                //this代表实例对象
                this.x = x;
                this.y = y;
                this.tohello = function () {
                    console.log("hello");
                }
            }
            //类的方法,不需要加上function这个关键字
            //下面代码中,toString方法是Point类内部定义的方法,它是不可枚举的。
            //这一点与 ES5 的行为不一致。
            toString() {
                return '(' + this.x + ', ' + this.y + ')';
            }
        
        }
        
        //完全可以看成构造函数的另外一种写法
        Point === Point.prototype.constructor // true
        
        //构造函数的prototype属性,在 ES6 的“类”上面继续存在。
        //事实上,类的所有方法都定义在类的prototype属性上面。
        //除非显示定义在类上面
        //类必须使用new调用,否则会报错。
        //这是它跟普通构造函数的一个主要区别,后者不用new也可以执行。
        let p = new Point('x', 'y');
        p.tohello();
        // p.prototype.tohello();  //false
        
        //与 ES5 一样,类的所有实例共享一个原型对象。
        var p1 = new Point(2, 3);
        var p2 = new Point(3, 2);
        
        p1.__proto__ === p2.__proto__
        //true
        //上面代码中,p1和p2都是Point的实例,它们的原型都是Point.prototype,所以__proto__属性是相等的。
        //这也意味着,可以通过实例的__proto__属性为“类”添加方法。
        //__proto__ 并不是语言本身的特性,这是各大厂商具体实现时添加的私有属性,
        //虽然目前很多现代浏览器的 JS 引擎中都提供了这个私有属性,
        //但依旧不建议在生产中使用该属性,避免对环境产生依赖。
        //生产环境中,我们可以使用 Object.getPrototypeOf 方法来获取实例对象的原型,然后再来为原型添加方法/属性。
        
        //不推荐下面的做法
        p1.__proto__.printName = function () {
            return 'Oops'
        };
        
        p1.printName() // "Oops"
        p2.printName() // "Oops"
        
        var p3 = new Point(4, 2);
        p3.printName() // "Oops"
        //类不存在变量提升(hoist),这一点与 ES5 完全不同。
        
        class Foo {
            //静态方法,只能通过类来调用
            //父类的静态方法也会被子类继承
            static classMethod() {
                return 'hello';
            }
        }
        
        Foo.classMethod() // 'hello'
        
        var foo = new Foo();
        //  foo.classMethod()
        // TypeError: foo.classMethod is not a function
        
        //实现继承
        class ColorPoint extends Point {
            constructor(x,y,color){
                //调用父类的构造函数,用来新建父类的this对象
                //super作为函数调用时,返回的是子类B的实例,super内部的this指向B
                //super相当于 A.prototype.constructor.call(this)
                //super作为函数只能用在constructor中
                super(x,y);
        
                //子类必须使用super方法,否则子类没有自己的this对象
                //继承父类的this对象然后进行加工
                this.color = color;
            }
        
            toString() {
                //super作为对象使用时,指向父类的原型对象。
                //在静态方法中指向父类
                //定义在父类实例上的方法是没办法用的
                return this.color + ' ' +super.toString();//调用父类的方法
            }
        }
        
        //可以使用getPrototypeOf方法来获取父类
        Object.getPrototypeOf(ColorPoint) === Point
        
        ColorPoint.__proto__ == Point; //true
        ColorPoint.prototype.__proto__ == Point.prototype;//true
        
        //这里和es5不一样
        //对象有属性__proto__,指向该对象的构造函数的原型对象。
        //方法除了有属性__proto__,还有属性prototype,prototype指向该方法的原型对象。
        
        var p1 = new Point(2, 3);
        var p2 = new ColorPoint(2, 3, 'red');
        
        // p2.__proto__ === p1.__proto__ // false
        p2.__proto__.__proto__ === p1.__proto__ // true
        
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值