在 java 、c# 等语言中,类是一种必须使用的”设计模式“,但是在 JavaScript 等语言中,它是可选的,并且在JavaScript中实现类总是会有各种缺陷。
还有要注意的一点是,JavaScript中没有类,只有对象,没有继承,只有委托(prototype)。
包括 es6 的 class 语法在内的各种语法糖,也不会改变这个事实。
首先要了解两个技巧
- 使用 call 方法调用父构造函数可以实现继承
- 用
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 29 30 31
| function Foo(who){ this.me = who } Foo.prototype.identify = function(){ return "I am " + this.me }
Foo.prototype.speak = function(){ console.log("Foo name is , " + this.identify() + ".") }
function Bar(who){ Foo.call(this,who) }
Bar.prototype = Object.create(Foo.prototype)
Bar.prototype.speak = function(){ console.log("Hello, " + this.identify() + ".") }
var b1 = new Bar("b1") var b2 = new Bar("b2") var f1 = new Foo("f1")
b1.speak() b2.speak() f1.speak()
|
但是如果父类修改了它的方法
1 2 3 4 5
| Foo.prototype.identify = function (){ return "Foo modified identify " + this.me } b1.speak()
|
委托风格
委托意味着某些对象找不到属性或者方式时,会把这个请求委托给另一个对象。
- 没有父子级的关系,无需继承。
- b1 把 speak 需要的一些行为放在 Foo 中,两个对象协同完成 speak 这一动作。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| Foo = { init: function (who) { this.me = who }, identify: function () { return 'I am ' + this.me } }
Bar = Object.create(Foo) Bar.speak = function () { console.log('Hello, ' + this.identify() + '.') }
var b1 = Object.create(Bar) b1.init('b1') var b2 = Object.create(Bar) b2.init('b2') b1.speak() b2.speak()
|
类的代码组织方式类似一棵树,是垂直的, 而委托的代码组织方式是并排的。
ps: 因为我工作使用的第一门语言就是 JavaScript ,中间也没有怎么用过OOP,所以对于 js 的这一套是很好接受的。