ES6 Class的基本语法与继承

1 Class 的基本语法

let methodName = 'getArea';
class MyClass {
  constructor(x, y) {
    this.x = x;
    this.y = y;
  }
  toString() {
    return '(' + this.x + ', ' + this.y + ')';
  }
  [methodName]() {
    // ...
  }
  get prop() {
    return 'getter';
  }
  set prop(value) {
    console.log('setter: '+value);
  }
}


// 报错
var point = Point(2, 3);

// 正确
var point = new Point(2, 3);

constructor

类的数据类型就是函数,类本身就指向构造函数。
类相当于实例的原型。

实例属性this._count定义在constructor()方法里面。另一种写法是,这个属性也可以定义在类的最顶层,其他都不变。

静态属性指的是 Class 本身的属性,即Class.propName,而不是定义在实例对象(this)上的属性。写法是在实例属性的前面,加上static关键字。

Point === Point.prototype.constructor // true
this指向

在构造方法中绑定this,这样就不会找不到方法了。

class Logger {
  constructor() {
    this.printName = this.printName.bind(this);
  }

  // ...
}

另一种解决方法是使用箭头函数。箭头函数内部的this总是指向定义时所在的对象。

class Obj {
  constructor() {
    this.getThis = () => this;
  }
}

const myObj = new Obj();
myObj.getThis() === myObj // true
方法

类的方法都定义在prototype对象上面。
Object.assign方法可以很方便地一次向类添加多个方法。

Object.assign(Point.prototype, {
  toString(){},
  toValue(){}
});

类的内部所有定义的方法,都是不可枚举的(non-enumerable)。

属性表达式:使用 [ ] 即可

getter和setter

在“类”的内部可以使用get和set关键字,对某个属性设置存值函数和取值函数,拦截该属性的存取行为。

类的实例

如果忘记加上new,像函数那样调用Class,将会报错。

class 表达式
const MyClass = class Me {
  getClassName() {
    return Me.name;
  }
};

上面代码使用表达式定义了一个类。需要注意的是,这个类的名字是Me,但是Me只在 Class 的内部可用,指代当前类。在 Class 外部,这个类只能用MyClass引用。
如果类的内部没用到的话,可以省略Me。

其他
  • 不存在提升
  • 都是严格模式
  • name属性
静态方法

类相当于实例的原型,所有在类中定义的方法,都会被实例继承。如果在一个方法前,加上static关键字,就表示该方法不会被实例继承,而是直接通过类来调用,这就称为“静态方法”。

如果静态方法包含this关键字,这个this指的是类,而不是实例。
静态方法可以与非静态方法重名。
父类的静态方法,可以被子类继承。

借助babal研究类的实现

转换前:

class Parent {
  constructor(a){
    this.filed1 = a;
  }
  filed2 = 2;
  func1 = function(){}
}

转换后:

function _classCallCheck(instance, Constructor) {
  if (!(instance instanceof Constructor)) {
    throw new TypeError("Cannot call a class as a function");
  }
}

var Parent = function Parent(a) {
  _classCallCheck(this, Parent);

  this.filed2 = 2;

  this.func1 = function () { };

  this.filed1 = a;
};

class的底层依然是构造函数。


2 Class 的继承

ES6 的继承机制完全不同,实质是先将父类实例对象的属性和方法,加到this上面(所以必须先调用super方法),然后再用子类的构造函数修改this。

class ColorPoint extends Point {
  constructor(x, y, color) {
    super(x, y); // 调用父类的constructor(x, y)
    this.color = color;
  }

  toString() {
    return this.color + ' ' + super.toString(); // 调用父类的toString()
  }
}

super方法
子类必须在constructor方法中调用super方法,否则新建实例时会报错。
实质是先将父类实例对象的属性和方法,加到this上面(所以必须先调用super方法),然后再用子类的构造函数修改this。

super对象
在普通方法中,指向父类的原型对象;在静态方法中,指向父类。

获取父类
Object.getPrototypeOf方法可以用来从子类上获取父类。

类的 prototype 属性和__proto__属性
Class 作为构造函数的语法糖,同时有prototype属性和__proto__属性,因此同时存在两条继承链。

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

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

继承的实现

转换前:

class Child extends Parent {
    constructor(a,b) {
      super(a);
      this.filed3 = b;
    }
  
  filed4 = 1;
  func2 = function(){}
}

转换后:

Child的实现:

var Child = function (_Parent) {
  _inherits(Child, _Parent);

  function Child(a, b) {
    _classCallCheck(this, Child);

    var _this = _possibleConstructorReturn(this, (Child.__proto__ || Object.getPrototypeOf(Child)).call(this, a));

    _this.filed4 = 1;

    _this.func2 = function () {};

    _this.filed3 = b;
    return _this;
  }

  return Child;
}(Parent);

es6实际上是为我们提供了一个“组合寄生继承”的简单写法。

参考文章:

  1. https://segmentfault.com/a/1190000017816134
  2. https://es6.ruanyifeng.com/#docs/class
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值