混合对象“类”

介绍面向类的设计模式:实例化(instantiation)、继承(inheritance)和 (相对)多态(polymorphism)。

类理论

类 / 继承描述了一种代码的组织结构形式——一种在软件中对真实世界中问题领域的建模
方法。

“类”设计模式

类并不是必须的编程基础,而是一种可选 的代码抽象。

JavaScript 提供了一些近似类的语法。

总结一下,在软件设计中类是一种可选的模式,你需要自己决定是否在 JavaScript 中使用 它。

类的机制

  • 构造:类实例是由一个特殊的类方法构造的,这个方法名通常和类名相同,被称为构造函数。这
    个方法的任务就是初始化实例需要的所有信息(状态)。

  • 类的继承:同理,定义好一个子类之后,相对于父类来说它就是一个独立并且完全不同的类。子类会 包含父类行为的原始副本,但是也可以重写所有继承的行为甚至定义新行为。

  • 多态:

    • 任何方法都
      可以引用继承层次中高层的方法(无论高层的方法名和当前方法名是否相同)。
    • 另一个方面是,在继承链的不同层次中一个方法名可以被多次定义,当调用方法时 会自动选择合适的定义。
  • 多重继承:有些面向类的语言允许你继承多个“父类”。多重继承意味着所有父类的定义都会被复制 到子类中。

  • 混入:一个对象并不会被复制到其他对 象,它们会被关联起来。由于在其他语言中类表现出来的都是复制行为,因此 JavaScript 开发者也想出了一个方法来 模拟类的复制行为,这个方法就是混入。

混入

JavaScript 开发者也想出了一个方法来 模拟类的复制行为,这个方法就是混入。接下来我们会看到两种类型的混入:显式和隐式。

显式混入

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// 非常简单的 mixin(..) 例子 :
function mixin( sourceObj, targetObj ) {
for (var key in sourceObj) {
// 只会在不存在的情况下复制 if (!(key in targetObj)) {
targetObj[key] = sourceObj[key];
}
}
return targetObj; }
var Vehicle = { engines: 1,
ignition: function() {
console.log( "Turning on my engine." );
},
drive: function() { this.ignition();
console.log( "Steering and moving forward!" );
}
};
var Car = mixin( Vehicle, { wheels: 4,
drive: function() { Vehicle.drive.call( this ); console.log(
"Rolling on all " + this.wheels + " wheels!"
);
} } );

函数实际上没有 被复制,复制的是函数引用

混合复制

1
2
3
4
5
6
7
8
9
10
11
12
13
// 另一种混入函数,可能有重写风险 function mixin( sourceObj, targetObj ) {
for (var key in sourceObj) { targetObj[key] = sourceObj[key];
}
return targetObj; }
var Vehicle = { // ...
};
// 首先创建一个空对象并把 Vehicle 的内容复制进去
var Car = mixin( Vehicle, { } );
// 然后把新内容复制到 Car 中 mixin( {
wheels: 4,
drive: function() { // ...
}
}, Car );

隐式混入

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
var Something = { cool: function() {
this.greeting = "Hello World";
this.count = this.count ? this.count + 1 : 1; }
};

Something.cool();
Something.greeting; // "Hello World"
Something.count; // 1
var Another = {
cool: function() {
// 隐式把 Something 混入 Another
Something.cool.call( this ); }
};
Another.cool();
Another.greeting; // "Hello World" Another.count; // 1(count不是共享状态)

小结

混入模式(无论显式还是隐式)可以用来模拟类的复制行为,但是通常会产生丑陋并且脆 弱的语法,比如显式伪多态(OtherObj.methodName.call(this, …)),这会让代码更加难 懂并且难以维护。

总地来说,在 JavaScript 中模拟类是得不偿失的,虽然能解决当前的问题,但是可能会埋 下更多的隐患。