ES6 class与ES5 function区别及联系

关于构造器constructor

function定义的构造函数中,其prototype.constructor属性指向构造器自身
class定义的类中,constructor其实也相当于定义在prototype属性上

class Point {
  constructor() {
    // ...这了可以定义实例属性
    this.a = 1;
  }

  toString() {
    // ...
  }

  toValue() {
    // ...
  }
}

// 等同于

Point.prototype = {
  constructor() {},
  toString() {},
  toValue() {},
};

重复定义

  • function会覆盖之前定义的方法
  • class会报错

原型或者类中方法的枚举

  • class中定义的方法不可用Object.keys(Point.prototype)枚举到
  • function构造器原型方法可被Object.keys(Point.prototype)枚举到,除过constructor
  • 所有原型方法属性都可用Object.getOwnPropertyNames(Point.prototype)访问到
class Point {
  constructor(x, y) {
    // ...
  }

  toString() {
    // ...
  }
}

Object.keys(Point.prototype)
// []
Object.getOwnPropertyNames(Point.prototype)
// ["constructor","toString"]
var Point = function (x, y) {
  // ...
};

Point.prototype.toString = function() {
  // ...
};

Object.keys(Point.prototype)
// ["toString"]
Object.getOwnPropertyNames(Point.prototype)
// ["constructor","toString"]

不管是class还是function,constructor属性默认不可枚举

都可通过实例的__proto__属性向原型添加方法

推荐使用Object.getPrototypeOf()获取实例原型后再添加方法

class没有变量提升

new Foo(); 
class Foo {}
VM21735:1 Uncaught ReferenceError: Foo is not defined
    at :1:1

class定义的类没有私有方法和私有属性

可以用symbol模拟

const bar = Symbol('bar');
const snaf = Symbol('snaf');

export default class myClass{

  // 公有方法
  foo(baz) {
    this[bar](baz);
  }

  // 私有方法
  [bar](baz) {//[bar]用方括号代表从表达式获取的属性名
    return this[snaf] = baz;
  }

  // ...
};

由于bar为symbol值,因此在外面不能当做函数使用。

this指向

class用类似于解构的方式获取原型上的方法

class Logger {
constructor(){}
  printName(name = 'there') {
    this.print(`Hello ${name}`);
  }

  print(text) {
    console.log(text);
  }
}

const logger = new Logger();
const { constructor,print,printName } = logger;

但是执行printName()时,他的this并不是指向当前实例,可在constructor中重新绑定:

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

class静态方法与静态属性

  • class定义的静态方法前加static关键字
  • 只能通过类名调用
  • 不能通过实例调用
  • 可与实例方法重名
  • 静态方法中的this指向类而非实例
  • 静态方法可被继承
  • 在子类中可通过super方法调用父类的静态方法
    class内部没有静态属性,只能在外面通过类名定义。

new.target

  1. new target属性指向当前的构造函数,不能在构造函数外部调用会报错,
function Person(name) {
console.log(new.target);
  if (new.target !== undefined) {
    this.name = name;
  } else {
    throw new Error('必须使用new生成实例');
  }
}
测试:
Person(123)
undefined
Uncaught Error: 必须使用new生成实例

2.继承时new.target返回子类

class Rectangle {
  constructor(length, width) {
    console.log(new.target === Rectangle);
    // ...
  }
}

class Square extends Rectangle {
  constructor(length) {
    super(length, length);
  }
}

var obj = new Square(3); // 输出 false

可构造不能被实例化的类,只能通过继承发挥作用:

class Shape {
  constructor() {
    if (new.target === Shape) {
      throw new Error('本类不能实例化');
    }
  }
}

class Rectangle extends Shape {
  constructor(length, width) {
    super();
    // ...
  }
}

var x = new Shape();  // 报错
var y = new Rectangle(3, 4);  // 正确

你可能感兴趣的:(es6)