site infoHacknerd | Tech Blog
blog cover

🌑 [ECMAScript6]23. Class继承

ES6JavaScript

简介

属性和方法的继承

可以继承静态方法 静态属性

不可以继承私有方法 私有属性

javascriptCopy
class Foo {
  #p = 1;
  #m() {
    console.log('hello');
  }
}

class Bar extends Foo {
  constructor() {
    super();
    console.log(this.#p); // 报错
    this.#m(); // 报错
  }
}

super关键字

__proto__ prototype

class作为构造函数的语法糖同时具有__proto__ 和 prototype 属性,class的__proto__ 是构造函数的继承,总是指向父类。prototype.__proto__ 是方法的继承总是指向父类的prototype。

image

继承的实现模式如下。

javascriptCopy
class A {...}
class B extends A {...}

Object.setPrototypeOf(B, A)
Object.setPrototypeOf(B.prototype, A.prototype)

// setPrototypeOf 方法实现
Object.setPrototypeOf = function (obj, proto) {
  obj.__proto__ = proto;
  return obj;
}

实例的__proto__属性

实例__proto__指向类 类的prototype 。所以实例的__proto__.__proto__ 指向父类prototype。所以子实例的__proto__.__proto__ 也指向父实例的__proto__ 。

javascriptCopy
class Point {...}
class ColorPoint extends Point {...}

var p1 = new Point(2, 3);
var p2 = new ColorPoint(2, 3, 'red');

p1.__proto__ === Point.prototype // true
p2.__proto__ === ColorPoint.prototype  // true

p2.__proto__.__proto__ === p1.__proto__ // true

image

原生构造函数的继承

ECMAScript中原生构造函数为。

  • Boolean()
  • Number()
  • String()
  • Array()
  • Date()
  • Function()
  • RegExp()
  • Error()
  • Object()
  • ES5 原生构造函数是不能继承的。比如

    javascriptCopy
    function MyArray() {
      Array.apply(this, arguments);
    }
    
    MyArray.prototype = Object.create(Array.prototype, {
      constructor: {
        value: MyArray,
        writable: true,
        configurable: true,
        enumerable: true
      }
    });
    
    var colors = new MyArray();
    colors[0] = "red";
    colors.length  // 0
    
    colors.length = 0;
    colors[0]  // "red"

    之所以会发生这种情况,是因为子类无法获得原生构造函数的内部属性,通过Array.apply()或者分配给原型对象都不行。原生构造函数会忽略apply方法传入的this,也就是说,原生构造函数的this无法绑定,导致拿不到内部属性。

    ES5 是先新建子类的实例对象this,再将父类的属性添加到子类上,由于父类的内部属性无法获取,导致无法继承原生的构造函数。比如,Array构造函数有一个内部属性[[DefineOwnProperty]],用来定义新属性时,更新length属性,这个内部属性无法在子类获取,导致子类的length属性行为不正常。

    ES6 允许继承原生构造函数定义子类,因为 ES6 是先新建父类的实例对象this,然后再用子类的构造函数修饰this,使得父类的所有行为都可以继承。下面是一个继承Array的例子。

    Minxin

    Contents

    • 简介
    • 属性和方法的继承
    • super关键字
    • __proto__ prototype
    • 原生构造函数的继承
    • Minxin

    2024/03/23 01:15