ES5/ES6原型链与继承

作者: 4dfab65f4d18 | 来源:发表于2017-12-11 14:44 被阅读160次

    ES5最经典的寄生组合式继承

    原型链相关.png

    注意

    如果A.prototype没有constructor,只要B.prototype的原型对象是A.prototype,则b instance of A就为true

    ES6和ES5继承的代码实现

    //ES5继承
    function Super(name){
        this.name=name
        this.colors=[1,2,3]
    }
    Super.prototype.sayName=function(){
        alert(this.name)
    }
    function Sub(name,age){
        Super.call(this,name)//显式传入this作为显示调用者调用父类构造函数
        this.age=age
    }
    Sub.prototype=Object.create(Super.prototype,{
        constructor:{
            value:Sub
        }
    })//避免调用父类的构造函数
    Sub.prototype.sayAge=function(){
        alert(this.age)
    }
    
    
    //ES6继承
    class Super{
        constructor(name){
            this.name=name
        }
        sayName(){
            alert(this.name)
        }
        static haha(){
            alert(this.hahatext)//Super函数对象的静态属性
        }
    }
    Super.hahatext="dingxu1"
    class Sub extends Super{
        constructor(name,age){
            super(name)//先实例化父构造函数,在更改this的指向,super()之后才有了this!
            this.age=age
        }
        sayAge(){
            alert(this.age)
        }
    }
    Sub.hahatext="dingxu2"
    Super.haha()//dingxu1
    Sub.haha()//dingxu2
    /***********************************************/
    Sub.__proto__ === Super // true 作为一个对象,子类(Sub)的原型(__proto__属性)是父类(Super)
    Sub.prototype.__proto__ === B.prototype // true 作为一个构造函数,子类(Sub)的原型对象(prototype属性)是父类的原型对象(prototype属性)的实例。
    
    
    • ES5 是先新建子类的实例对象this,再将父类的属性添加到子类上,由于父类的内部属性无法获取,导致无法继承原生的构造函数。比如,Array构造函数有一个内部属性[[DefineOwnProperty]],用来定义新属性时,更新length属性,这个内部属性无法在子类获取,导致子类的length属性行为不正常。
    • ES6 允许继承原生构造函数定义子类,因为 ES6 是先新建父类的实例对象this,然后再用子类的构造函数修饰this,使得父类的所有行为都可以继承。下面是一个继承Array的例子。
    class MyArray extends Array{
        constructor(...args){
            super(...args)
        }
    }
    var arr=new MyArray()
    arr[0]=12
    arr.length
    arr.length=0
    arr[0]
    

    extends关键字不仅可以用来继承类,还可以用来继承原生的构造函数。因此可以在原生数据结构的基础上,定义自己的数据结构。

    class VersionedArray extends Array {
      constructor() {
        super();
        this.history = [[]];
      }
      commit() {
        this.history.push(this.slice());
      }
      revert() {
        this.splice(0, this.length, ...this.history[this.history.length - 1]);
      }
    }
    
    var x = new VersionedArray();
    
    x.push(1);
    x.push(2);
    x // [1, 2]
    x.history // [[]]
    
    x.commit();
    x.history // [[], [1, 2]]
    
    x.push(3);
    x // [1, 2, 3]
    x.history // [[], [1, 2]]
    
    x.revert();
    x // [1, 2]
    

    注意,继承Object的子类,有一个行为差异。

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

    上面代码中,NewObj继承了Object,但是无法通过super方法向父类Object传参。这是因为 ES6 改变了Object构造函数的行为,一旦发现Object方法不是通过new Object()这种形式调用,ES6 规定Object构造函数会忽略参数。

    相关文章

      网友评论

      • 4dfab65f4d18:文章参考了阮一峰的ES6,错误之处请指出:yum:

      本文标题:ES5/ES6原型链与继承

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