es6学习笔记-class之继承 (2)

子类Child当中的super.p(),就是将super当作一个对象使用。这时,super在普通方法之中,指向Person.prototype,所以super.p()就相当于Person.prototype.p()。super.p() == Person.prototype.p() 如上

在子类普通方法中通过super调用父类的方法时,方法内部的this指向当前的子类实例。super.say()虽然调用的是Person.prototype.say(),但是Person.prototype.say()内部的this指向子类Child的实例,导致输出的是25,而不是2。也就是说,实际上执行的是super.say.call(this)。如上
由于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 } } let b = new B(); super.x赋值为3,这时等同于对this.x赋值为3。而当读取super.x的时候,读的是A.prototype.x,所以返回undefined。
大白话:就是A.prototype中没有x,从A类的中看到,只有构造函数constructor,没有其他方法了。

由于super指向父类的原型对象,所以定义在父类实例上的方法或属性,是无法通过super调用的。如下:

class A { constructor() { this.p = 2; } } A.prototype.q = 4 class B extends A { m() { return super.p; } n(){ return super.q } } let b = new B(); b.m() // undefined b.q // 4 p是父类A实例的属性,但super.p就引用不到它。属性q是定义在A.prototype上面的,所以super.q可以取到它的值。

super用在静态方法之中,这时super将指向父类。在普通方法之中指向父类的原型对象。**********

class Parent { static myMethod(msg) { console.log('static', msg); } myMethod(msg) { console.log('instance', msg); } } class Child extends Parent { static myMethod(msg) { super.myMethod(msg); } myMethod(msg) { super.myMethod(msg); } } Child.myMethod(1); // static 1 var child = new Child(); child.myMethod(2); // instance 2

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

Object.getPrototypeOf()

用来判断一个类是否继承了另一个类。

class A { static hello() { console.log('hello world'); } } class B extends A { constructor(color){ super(); this.color = color } } var red = new B('red'); red instanceof B // true red instanceod A // true Object.getPrototypeOf(B) === A // true B.hello() // hello world

由上面的例子可知:red既是A的实例又是B的实例,通过Object.getPrototypeOf(B)判断了是继承A的,同样的静态方法也可以继承的

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

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

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

class A {} class B extends A {} B.__proto__ === A // true B.prototype.__proto__ === A.prototype // true

原因如下:

Object.setPrototypeOf = function (obj, proto) { obj.__proto__ = proto; return obj; } class A {} class B {} // B 的实例继承 A 的实例 Object.setPrototypeOf(B.prototype, A.prototype); // 等同于 B.prototype.__proto__ = A.prototype; // B 继承 A 的静态属性 Object.setPrototypeOf(B, A); // 等同于 B.__proto__ = A;

这两条继承链,可以这样理解:作为一个对象,子类(B)的原型(__proto__属性)是父类(A);作为一个构造函数,子类(B)的原型对象(prototype属性)是父类的原型对象(prototype属性)的实例。
另外还有两种情况:

子类继承Object类。

class A extends Object {} A.__proto__ === Object // true A.prototype.__proto__ === Object.prototype // true

不存在任何继承。

class A {} A.__proto__ === Function.prototype // true A.prototype.__proto__ === Object.prototype // true

A作为一个基类(即不存在任何继承),就是一个普通函数,所以直接继承Function.prototype。但是,A调用后返回一个空对象(即Object实例),所以A.prototype.__proto__指向构造函数(Object)的prototype属性。

实例的 proto 属性

子类实例的__proto__属性的__proto__属性,指向父类实例的__proto__属性。也就是说,子类实例的原型的原型,是父类的原型。

class Point{ constructor(x,y){ this.x = x; this.y = y; } printName(){ console.log('hahahah') } } class ColorPoint extends Point{ constructor(x,y,color){ super(x,y); this.color = color } printName(){ super.printName() } } var p1 = new Point(2, 3); var p2 = new ColorPoint(2, 3, 'red'); p2.__proto__ === p1.__proto__ // false p2.__proto__.__proto__ === p1.__proto__ // true p2.__proto__.__proto__.printName = function () { console.log('Ha'); }; p1.printName() // "Ha"

由例子可知:

ColorPoint继承了Point,导致前者原型的原型是后者的原型。

在ColorPoint的实例p2上向Point类添加方法,结果影响到了Point的实例p1。

最后

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wpjzfp.html