# 类和构造函数
9.1 常用
class
,避免直接操作prototype
Why?
class
语法更简洁更易理解// bad function Queue(contents = []) { this.queue = [...contents]; } Queue.prototype.pop = function () { const value = this.queue[0]; this.queue.splice(0, 1); return value; }; // good class Queue { constructor(contents = []) { this.queue = [...contents]; } pop() { const value = this.queue[0]; this.queue.splice(0, 1); return value; } }
9.2 用
extends
实现继承Why? 它是一种内置的方法来继承原型功能而不打破
instanceof
// bad const inherits = require('inherits'); function PeekableQueue(contents) { Queue.apply(this, contents); } inherits(PeekableQueue, Queue); PeekableQueue.prototype.peek = function () { return this._queue[0]; } // good class PeekableQueue extends Queue { peek() { return this._queue[0]; } }
9.3 方法可以返回
this
来实现方法链// bad Jedi.prototype.jump = function () { this.jumping = true; return true; }; Jedi.prototype.setHeight = function (height) { this.height = height; }; const luke = new Jedi(); luke.jump(); // => true luke.setHeight(20); // => undefined // good class Jedi { jump() { this.jumping = true; return this; } setHeight(height) { this.height = height; return this; } } const luke = new Jedi(); luke.jump() .setHeight(20);
9.4 写一个定制的toString()方法是可以的,只要保证它是可以正常工作且没有副作用的
class Jedi { constructor(options = {}) { this.name = options.name || 'no name'; } getName() { return this.name; } toString() { return `Jedi - ${this.getName()}`; } }
9.5 如果没有具体说明,类有默认的构造方法。一个空的构造函数或只是代表父类的构造函数是不需要写的。 eslint:
no-useless-constructor
(opens new window)// bad class Jedi { constructor() {} getName() { return this.name; } } // bad class Rey extends Jedi { // 这种构造函数是不需要写的 constructor(...args) { super(...args); } } // good class Rey extends Jedi { constructor(...args) { super(...args); this.name = 'Rey'; } }
9.6 避免重复类成员。 eslint:
no-dupe-class-members
(opens new window)Why? 重复类成员会默默的执行最后一个 —— 重复本身也是一个bug
// bad class Foo { bar() { return 1; } bar() { return 2; } } // good class Foo { bar() { return 1; } } // good class Foo { bar() { return 2; } }