Skip to content
imshengli blog
Go back

ES6 Class

简介

生成实例的传统方法:通过构造函数; ES6 引入了class,作为“对象的模板”;通过class,定义类。 基本上,ES6 的class可以看作只是一个语法糖,

代码分析

const methodName = 'getArea';
function bar2(baz) {
  return this.snaf = baz;
}
const bar3 = Symbol('bar3');
const snaf3 = Symbol('snaf3');

// 通过`class`关键字定义类
class Point {
  // 类内部,默认是严格模式;所以不用写“use strict”

  // `constructor` 构造方法;
  // 一个类默认有 `constructor` 方法;
  // 默认返回实例对象,即 this,完全可以指定返回另外一个对象;
  constructor(x, y) {
    // this 代表 实例对象
    // this,它默认指向类的实例
    this.x = x;
    this.y = y;

    // this 的指向
    // 如果 printName 中使用 this,单独使用 printName 方法时,需要设置
    this.printName = this.printName.bind(this);
    // 还可以使用箭头函数
    this.printName = (name = 'there') => {
      this.print(`Hello ${name}`);
    };
    // 还有一种方法,使用 Proxy
    // 获取方法的时候,自动绑定 this
    // [Todos]

    // new.target 属性
    // 返回 new 命令作用于的那个构造函数
    // 可以用来确保构造函数只能用 new 命令调用
    // 可以写出不能独立使用、必须继承后才能使用的类。
    // 例如
    if (new.target === Point) {
      throw new Error('本类不能实例化');
    }
  }

  // 为了说明 this 的问题
  printName(name = 'there') {
    this.print(`Hello ${name}`);
  }
  print(text) {
    console.log(text);
  }

  // 定义类的方法
  // 其实是定义在类的`prototype`属性上面;
  // 类内部定义的所有方法,都是不可枚举的;Object.keys(Point.prototype),这与ES5有差异;
  toString() {
    return '(' + this.x + ', ' + this.y + ')';
  }

  // 类的属性名,可以采用表达式。
  [methodName]() {
    // ...
  }

  // 私有方法1:通过命名加以区别
  _bar1(baz) {
    return this.snaf = baz;
  }
  // 私有方法2:将方法移出模块
  foo2(baz) {
    bar2.call(this, baz);
  }
  // 私有方法3:利用Symbol值的唯一性
  [bar3](baz) {
    return this[snaf3] = baz3;
  }

  // 私有属性,目前 ES6 还不提供

  // getter 和 setter
  // 在“类”的内部可以使用get和set关键字,
  // 对某个属性设置存值函数和取值函数,拦截该属性的存取行为。
  get prop() {
    return 'getter';
  }
  set prop(value) {
    console.log('setter: '+value);
  }
  // 存值函数和取值函数是设置在属性的 Descriptor 对象上的。
  // Descriptor 对象?
  // [Todos]

  // Generator 方法
  // 方法前加上星号
  * [Symbol.iterator]() {
    for (let arg of this.x) {
      yield arg;
    }
  }

  // 静态方法
  // 该方法不会被实例继承,而是直接通过类来调用
  // 父类的静态方法,可以被子类继承
  // 子类可以通过 super 对象,调用父类的静态方法
  static classMethod() {
    // this, 静态方法的 this 指的是类,而不是实例
    return 'hello';
  }

  // 静态属性和实例属性
  // 新提案
  // 实例属性
  state = {
    count: 0
  };
  // 静态属性
  static myStaticProp = 42;

}

typeof Point; // "function"
Point === Point.prototype.constructor // true

// name属性总是返回紧跟在class关键字后面的类名。
Point.name; // "Point"

// 静态属性
// ES6 明确规定,Class 内部只有静态方法,没有静态属性。
// 只能通过这种方式定义
Point.prop = 1;

// 类使用时,必须通过 new 调用,否则会报错;
// 这也是和普通构造函数不同的地方;
const p1 = new Point(5, 10); // 创建实例
const p2 = new Point(10, 10);

// 实例的属性:除非显式定义在其本身(this),否则都在定义在原型上;
p1.hasOwnProperty('x'); // true
p1.hasOwnProperty('toString'); // false
p1.__proto__.hasOwnProperty('toString') // true

// 所有实例共享一个原型;
p1.__proto__ === p2.__proto__; // true

一次添加多个方法

// 类的方法都定义在prototype对象上面,
// 所以类的新方法可以添加在prototype对象上面。
// 一次向类添加多个方法
Object.assign(Point.prototype, {
    toString() {},
    toValue() {}
});

class 表达式

// 这个类的名字是MyClass
const MyClass = class Me {
  getClassName() {
    return Me.name;
  }
};
let inst = new MyClass();
inst.getClassName(); // Me
// Me 只在 Class 的内部代码可用,指代当前类。
Me.name // ReferenceError: Me is not defined
// 简写
const MyClass = class { /* ... */ };

class 不存在变量提升

new Foo(); // ReferenceError
class Foo {};
// 不存在变量提升的原因是:与继承有关,必须保证子类在父类之后定义。
{
  let Foo = class {};
  class Bar extends Foo {
  }
}

Share this post on:

Previous Post
ES6 Object
Next Post
ES6 Class Extends