new是从构造函数生成实例的命令。 ES6 为new命令引入了一个new.target属性,( 在构造函数中) 返回new命令作用于的那个构造函数。 如果构造函数不是通过new命令调用的, new.target会返回undefined, 因此这个属性可以用来确定构造函数是怎么调用的。
- function Person(name) {
- if(new.target !== undefined) {
- this.name = name;
- } else {
- throw new Error(' 必须使用 new 生成实例 ');
- }
- }
- // 另一种写法
- function Person(name) {
- if(new.target === Person) {
- this.name = name;
- } else {
- throw new Error(' 必须使用 new 生成实例 ');
- }
- }
- var person = new Person(' 张三 '); // 正确
- var notAPerson = Person.call(person, ' 张三 '); // 报错
Class 内部调用new.target, 返回当前 Class。
- class Rectangle {
- constructor(length, width) {
- console.log(new.target === Rectangle);
- this.length = length;
- this.width = width;
- }
- }
- var obj = new Rectangle(3, 4); // 输出 true
- 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); // 正确
注意, 在函数外部, 使用new.target会报错。
Mixin 模式的实现
Mixin 模式指的是, 将多个类的接口“ 混入”( mixin)另一个类。 它在 ES6 的实现如下。
- function mix(...mixins) {
- class Mix {}
- for(let mixin of mixins) {
- copyProperties(Mix, mixin);
- copyProperties(Mix.prototype, mixin.prototype);
- }
- return Mix;
- }
- function copyProperties(target, source) {
- for(let key of Reflect.ownKeys(source)) {
- if(key !== "constructor" &&
- key !== "prototype" &&
- key !== "name"
- ) {
- let desc = Object.getOwnPropertyDescriptor(source, key);
- Object.defineProperty(target, key, desc);
- }
- }
- }
- lass DistributedEdit extends mix(Loggable, Serializable) {
- // ...
- }