JavaScript 如何面向对象编程?

面向对象编程(Object-Oriented Programming)是基于对象的一种编程范式(paradigm)。其有三个广为人知的特性,封装(Encapsulation)、继承(Inheritance)和多态(Polymorphism),让编程更灵活、可维护。常见的面向对象编程方式都是基于类(class)的,在 C++、Java 等高级语言中都以类的形式得到实现。

在 JavaScript(以下简称 JS)是基于对象的弱类型语言,并无类的概念,但其提供了原型机制,可用来支持面向对象编程。下面分别用 JS 实现 OOP 三大特性。

封装

之前我一直以为封装指的是方法与数据能放在一起(类),但一看维基百科才得知,封装是一种限制外部直接访问对象内部数据与方法的语言机制。在 C++ 中,封装就是通过 publicprivate(和 protected) 来实现的。

JS 中并没有提供该机制,但可以借助闭包来实现私有变量与方法。

1
2
3
4
5
6
7
8
9
10
11
function foo () {
let name = 'Hankey'
this.getName = () => name;
this.setName = n => { name = n };
}
let fool = new foo()
fool.name // undefined
fool.getName() // Hankey
fool.setName('Mr.Hankey')
fool.getName() // Mr.Hankey

继承

JS 没有类这个概念,但却提供了原型链(Prototype Chain)机制,使得继承成为可能。关于原型这里且不细谈。(BTW,Self 是第一个实现原型的编程语言)

虽说都是使用原型,但不同的使用方法会形成各样的继承方式。目前最为完善的似乎就是组合寄生式继承了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
function papa (name) { // 被 Stranger Things 影响了 :sob:
this.name = name
}
papa.prototype.toString = function _toString () {
console.log('Papa is ' + this.name + '!')
}
function baby (name, gender) {
papa.call(this, name) // 组合
this.gender = gender
}
baby.prototype = Object.create(papa.prototype) // 寄生
baby.prototype.constructor = baby // 修复重写原型导致的混乱
baby.prototype.toString2 = function _toString2 () {
console.log('Baby named ' + this.name + ', is a ' + this.gender + '.');
}
var eleven = new baby('11', 'girl')
eleven.toString() // Papa is 11!
eleven.toString2() // Baby named 11, is a girl.

Object.create(obj, [properties]) 在做的就是创建一个原型为 obj 的对象。它实际上做的事情基本如下:

1
2
3
4
5
function create (obj) {
function F () {}
F.prototype = obj
return new F()
}

多态

参考资料

  1. Object-oriented programming
  2. Encapsulation
  3. Inheritance
  4. Prototype-based programming
Comments