下面是生成子类实例的代码。
let cp = new ColorPoint(25, 8, 'green'); cp instanceof ColorPoint // true cp instanceof Point // true
上面代码中, 实例对象cp同时是ColorPoint和Point两个类的实例, 这与 ES5 的行为完全一致。
2. 类的 prototype 属性和 __proto__ 属性
大多数浏览器的 ES5 实现之中, 每一个对象都有__proto__属性, 指向对应的构造函数的 prototype 属性。 Class 作为构造函数的语法糖, 同时有prototype 属性和__proto__属性, 因此同时存在两条继承链。
( 1) 子类的__proto__属性, 表示构造函数的继承, 总是指向父类。
( 2) 子类prototype属性的__proto__属性, 表示方法的继承, 总是指向父类的prototype属性。
class A {} class B extends A {} B.__proto__ === A // true B.prototype.__proto__ === A.prototype // true
上面代码中, 子类B的__proto__属性指向父类A, 子类B的prototype属性的__proto__属性指向父类A的prototype属性。
这样的结果是因为, 类的继承是按照下面的模式实现的。
class A {} class B {} // B 的实例继承 A 的实例 Object.setPrototypeOf(B.prototype, A.prototype); // B 继承 A 的静态属性 Object.setPrototypeOf(B, A);
《对象的扩展》 一章给出过Object.setPrototypeOf
方法的实现。
Object.setPrototypeOf = function(obj, proto) { obj.__proto__ = proto; return obj; }
因此, 就得到了上面的结果。
Object.setPrototypeOf(B.prototype, A.prototype); // 等同于 B.prototype.__proto__ = A.prototype; Object.setPrototypeOf(B, A); // 等同于 B.__proto__ = A;
这两条继承链, 可以这样理解: 作为一个对象, 子类( B) 的原型( __proto__属性) 是父类( A); 作为一个构造函数, 子类( B) 的原型( prototype属性) 是父类的实例。
Object.create(A.prototype); // 等同于 B.prototype.__proto__ = A.prototype;
3. Extends 的继承目标
extends关键字后面可以跟多种类型的值。
class B extends A {}
上面代码的A, 只要是一个有prototype属性的函数, 就能被B继承。 由于函数都有prototype属性( 除了Function.prototype
函数), 因此A可以是任意函数。
下面, 讨论三种特殊情况。
第一种特殊情况, 子类继承 Object 类。
class A extends Object {} A.__proto__ === Object // true A.prototype.__proto__ === Object.prototype // true
内容版权声明:除非注明,否则皆为本站原创文章。