• 技术文章 >web前端 >js教程

    ECMAScript 6中类继承解析(附示例)

    不言不言2018-10-25 15:36:53转载834
    本篇文章给大家带来的内容是关于ECMAScript 6中类继承解析(附示例),有一定的参考价值,有需要的朋友可以参考一下,希望对你有所帮助。

    类继承

    看类继承前,先回顾构造函数怎么实现对象的继承的

            function F() {
                this.a = 1;
            }
            function Son() {
                F.call(this);
            } 
            function inherit(S, F) {
                S.prototype = Object.create(F.prototype);
                S.prototype.constructor = S;
            }
            inherit(Son, F);
            let son = new Son();

    它实现了哪几个功能:

    继承F的this属性也就是F实例对象的属性

    Son.prototype.__proto__ === F.prototype 实现了上下辈分的继承

    son.constructor让son认祖归宗

    同样类继承也是如此

    用来extends和super关键字,看一个简单的继承

            class A {
                constructor() {
                    this.a = 1;
                }
            }
            class B extends A {
                constructor() {
                    super();
                    this.b = 2;
                }
                m() {
    
                }
            }
            let b = new B();

    同样实现了那三点基本功能

    B {a: 1, b: 2}
    b.__proto__  == B.prototype
    b.__proto__.__proto__ === A.prototype
    b.constructor === B

    我认为:关键字extends实现了原型的继承,以及constructor的修正;关键字super实现了父类this的继承,这里的super相当于A.prototype.constructor.call(this)

    注意点

    写了constructor,就必须在里面写super,不然new子类实例对象会报错;要么都不写;其次子类的中constructor中的this属性必须写在super后面

    1.ES5 的继承,实质是先创造子类的实例对象this,然后再将父类的方法添加到this上面(Parent.apply(this))。ES6 的继承机制完全不同,实质是先将父类实例对象的属性和方法,加到this上面(所以必须先调用super方法),然后再用子类的构造函数修改this
    2.因为子类自己的this对象,必须先通过父类的构造函数完成塑造,得到与父类同样的实例属性和方法,然后再对其进行加工,加上子类自己的实 例属性和方法。如果不调用super方法,子类就得不到this对象。

            class B extends A {
                constructor() {    //要么都不写,new时默认会自动生成
                    super();
                    this.b = 2;    //写在super后面
                } 
                m() {
    
                }
            }

    super的各种指向问题

    super作为函数,只能放在子类的constructor中,指向A.prototype.constructor.call(this)

    super作为对象,在子类普通方法中调用,super就是父类的原型也就是A.prototype;所以只能调用原型链上的方法,不能动用父类实例的方法和属性constructor{}中的不能调用

            class A {
                constructor() {
    
                    this.a = 1;
                }
                n() {
    
                    return this;
                }
            }
            class B extends A {
                constructor() {
                    
                    super();
                    this.b = 2;
                    
                }
                m() {
                    return super.n();
                }
            }
            let b = new B();
            b === b.m();

    并且规定

    在子类普通方法中通过super调用父类的方法时,方法内部的this指向当前的子类实例。

    所以上面return this 就是返回子类实例对象

    super作为对象对属性赋值时
    super相当于this,赋值属性也就成了子类实例的属性

    class A {
      constructor() {
        this.x = 1;
      }
    }
    
    class B extends A {
      constructor() {
        super();
        this.x = 2;
        super.x = 3;
        console.log(super.x); // undefined
        console.log(this.x); // 3
        console.log(super.valueOf() instanceof B);   //true
      }
    }
    
    let b = new B();

    super作为对象,在静态方法中指向的是父类能调用父类的静态方法,如果方法内部有this则指向当前的子类
    只有类才能调用类的静态方法

            class A {
                constructor() {
    
                    this.a = 1;
                }
                static n() {
    
                    return this;
                }
            }
            class B extends A {
                constructor() {
                    
                    super();
                    this.b = 2;
                    
                }
                static m() {
                    return super.n();
                }
            }
            console.log(A.n() === A)   // true
            console.log(B === B.m());  //true
    由于对象总是继承其他对象的,所以可以在任意一个对象中,使用super关键字。
    var obj = {
      toString() {
        return "MyObject: " + super.toString();
      }
    };
    Object.getPrototypeOf(obj).toString = function () {
        return "这里super等于obj.__proto__";
    }
    console.log(obj.toString());        //MyObject: 这里super等于obj.__proto__

    类的prototype与__proto__

    (1)子类的__proto__属性,表示构造函数的继承,总是指向父类。

    (2)子类prototype属性的__proto__属性,表示方法的继承,总是指向父类的prototype属性。

    类的继承模式

    class A {
    }
    
    class B {
    }
    
    // B 的实例继承 A 的实例
    Object.setPrototypeOf(B.prototype, A.prototype);
    
    // B 继承 A 的静态属性
    Object.setPrototypeOf(B, A);
    
    const b = new B();

    也是因为这种实现所以类能调用自己的静态方法

    es6实现了原始构造函数的继承

    之前Array.apply(this)this并不会塑造Array里面的内部结构,所以我们当我们用类数组对象引用数组方法时用null代替了
    而es6用类实现它的继承,
    代码摘自es6入门

    class MyArray extends Array {
      constructor(...args) {
        super(...args);
      }
    }
    
    var arr = new MyArray();
    arr[0] = 12;
    arr.length // 1
    
    arr.length = 0;
    arr[0] // undefined

    需要注意的是

    ES6 改变了Object构造函数的行为,一旦发现Object方法不是通过new Object()这种形式调用,ES6 规定Object构造函数会忽略参数。

    class NewObj extends Object{
      constructor(){
        super(...arguments);
      }
    }
    var o = new NewObj({attr: true});
    o.attr === true  // false

    传入参数会无效的

    以上就是ECMAScript 6中类继承解析(附示例)的详细内容,更多请关注php中文网其它相关文章!

    声明:本文转载于:segmentfault,如有侵犯,请联系admin@php.cn删除
    专题推荐:es6-系列 javascript
    上一篇:ES6的Symbol的用法详解(附代码) 下一篇:javascript函数表达式的特征以及递归的理解(附示例)
    Web大前端开发直播班

    相关文章推荐

    • 深入浅出ES6之let和const命令• ES6学习之变量的解构赋值• 详细介绍ES6新特性 -JavaScript中的Map和WeakMap对象的代码实例• ES6新特性:JavaScript中内置的延迟对象Promise 代码详细介绍• ES6新特性开发微信小程序(4)

    全部评论我要评论

  • 取消发布评论发送
  • 1/1

    PHP中文网