面向对象程序设计(简称 OOP)是现在最流行的程序设计方法,JavaScript 的核心是支持面向对象的,Prototype 是 JavaScript 实现与管理继承的一种机制。最近在读《你不知道的 JavaScript》一书中了解到除了使用类实现外,还可以用一种“对象关联”(OLOO,objects linked to other objects)的编程风格
在 JavaScript 中定义一个类的传统方法是通过构造函数。可以这样写:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| function Foo(name) { this.name = name; }
Foo.prototype.getName = function() { console.log(`name:${this.name}`); };
function Bar(name, age) { Foo.call(this, name);
this.age = age; }
Bar.prototype = Object.create(Foo.prototype); Bar.prototype.constructor = Bar;
Bar.prototype.speak = function() { console.log(`My name is ${this.name}, age ${this.age}`); };
const b1 = new Bar('Zubin', 10); const b2 = new Bar('Jake', 15);
b1.getName(); b1.speak(); b2.getName(); b2.speak();
|
ES6 提供了更接近传统语言的写法,引入了 Class(类)这个概念,作为对象的模板。通过 class 关键字,可以定义类。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| class Foo { constructor(name) { this.name = name; }
getName() { console.log(`name:${this.name}`); } }
class Bar extends Foo { constructor(name, age) { super(name); this.age = age; }
speak() { console.log(`My name is ${this.name}, age ${this.age}`); } }
const b1 = new Bar('Zubin', 10); const b2 = new Bar('Jake', 15);
b1.getName(); b1.speak(); b2.getName(); b2.speak();
|
最后是《你不知道的 JavaScript》一书中作者提倡的一种 OLOO 的风格,使用 Object.create() 方法直接生成实例。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| const Foo = { init(name) { this.name = name; }, getName() { console.log(`name:${this.name}`); }, };
const Bar = Object.create(Foo); Bar.init = function(name, age) { this.name = name; this.age = age; }; Bar.speak = function() { console.log(`My name is ${this.name}, age ${this.age}`); };
const b1 = Object.create(Bar); b1.init('Zubin', 10);
const b2 = Object.create(Bar); b2.init('Jake', 15);
b1.getName(); b1.speak(); b2.getName(); b2.speak();
|
从书里的描述来看,作者的观点是 OLOO 总比 Class 的形式要好。如果你只读这本书,那么结论必然是我们不需要传统的 class 形式。个人认为 Class 未必就像书中所说的那样不堪,现实中有几点需要考虑:
- Class 在构建对象实例时使用约定成俗的 new 方法,风格更加统一,OLOO 写法中的 init 方法是自己定义的
1 2 3 4 5 6
| var f = new Foo(123, 'abc');
var f = Object.create(Foo); f.init(123, 'abc');
|
基于 Class 的面向对象的写法是“主流”,毕竟在项目中代码不是你一个人看的。
Class 对于大部分人(尤其是后端程序员)更容易接受。
Class 是基于 prototype 更为严格和易用的语法糖,目的是为了 改善 原来 prototype 丑和难用,但是 C++ 和 Java 中的类 跟 js 中的类不是一回事 它们的继承,封装,多态在 js 的类中是不存在的。当然利用 TypeScript 的 Interface 来实现“面向 Interface 编程”也不错的选择。