资讯专栏INFORMATION COLUMN

ECMAScript 6入门类继承笔记

_DangJin / 628人阅读

类继承

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

        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
传入参数会无效的

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/98679.html

相关文章

  • ECMAScript 6入门学习笔记

    摘要:类基本概念,记录以便自己后面加深理解了解类是什么是什么不妨写一个看看的原型可以看到这三个属性都是不可遍历的并且与类相比就多了一个原型链。和静态方法中是一样的得是哪个类就返回哪个类本类不能实例化报错正确 类class 基本概念,记录以便自己后面加深理解 了解类是什么 class是什么?不妨写一个看看 class Demo { constructor() { thi...

    asoren 评论0 收藏0
  • ECMAScript 6入门读书笔记

    摘要:变量的解构赋值更加便利的从匿名对象或者数组中,对变量进行赋值数组的解构赋值基本样式,右边数据类型必须是可迭代的类型。 变量的解构赋值 更加便利的从匿名对象或者数组中,对变量进行赋值; 数组的解构赋值 基本样式,右边数据类型必须是可迭代的类型。 let a = 1, b = 2, c = 3; //等价于 //let [a, b, c] = [1, 2, 3]; 对...

    wawor4827 评论0 收藏0
  • ES6 Iterator笔记(摘抄至阮一峰的ECMAScript 6入门

    摘要:也就是说,遍历器对象本质上,就是一个指针对象。执行这个函数,就会返回一个遍历器。一个对象如果要有可被循环调用的接口,就必须在的属性上部署遍历器生成方法原型链上的对象具有该方法也可。后面跟的是一个可遍历的结构,它会调用该结构的遍历器接口。 ES6 Iterator笔记(摘抄至阮一峰的ECMAScript 6入门) Iterator的遍历过程 创建一个指针对象,指向当前数据结构的起始位...

    mayaohua 评论0 收藏0
  • ECMAScript 6入门扩展笔记

    摘要:字符串扩展相关补充引入来表示码点,之前只能表示引入能正确读取大于的编码引入用于读取大于的字符的编码例如 字符串扩展 Unicode相关补充 引入u{xx}来表示码点,之前只能表示u0000-uffff引入String.fromCodePoint()能正确读取大于uFFFF的unicode编码引入s.codePiointAt()用于读取大于0xFFFF的字符的unicode编码例如let...

    孙淑建 评论0 收藏0
  • ECMAScript 6 入门》读书笔记

    摘要:阮一峰老师开源作品。书上的示例代码可以通过在线网站代码调试工具调试。 阮一峰老师开源作品。 书上的示例代码可以通过 在线网站代码调试工具 JS Bin 调试。 作用域 作用域链 每个变量或函数通过执行环境 (execution context) 定义了其有权访问的其他数据,决定了他们各自的行为; 全局执行环境是最顶层的执行环境,根据宿主环境的不同,表示全局执行环境的对象也不同:在浏览...

    qieangel2013 评论0 收藏0

发表评论

0条评论

_DangJin

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<