第四章 混核对象“类”
1、理论
面向对象编程强调的是数据和操作数据的行为本质上是互相关联的。实例化,继承,多态性
javascript中只有对象,并不存在可以被实例化的“类”。一个对象并不会被复制到其他对象,他们会被关联起来,由于其他语言中类表现出来的都是复制行为,因此js开发者也想出一个方法来模拟类的复制行为——混入。混入有两种类型:显式和隐式。
2、显式混入
1 // 非常简单的 mixin(..) 例子 : 2 function mixin( sourceObj, targetObj ) { 3 for (var key in sourceObj) { 4 // 只会在不存在的情况下复制 5 if (!(key in targetObj)) { 6 targetObj[key] = sourceObj[key]; 7 } 8 } 9 return targetObj; 10 } 11 var Vehicle = { 12 engines: 1, 13 ignition: function() { 14 console.log( "Turning on my engine." ); 15 }, 16 drive: function() { 17 this.ignition(); 18 console.log( "Steering and moving forward!" ); 19 } 20 }; 21 var Car = mixin( Vehicle, { 22 wheels: 4, 23 drive: function() { 24 Vehicle.drive.call( this ); 25 console.log( 26 "Rolling on all " + this.wheels + " wheels!" 27 ); 28 } 29 } );
注意:
我们处理的已经不再是类了,因为在 JavaScript 中不存在类,Vehicle 和 Car 都是对象,供我们分别进行复制和粘贴。
Vehicle.drive.call( this ) 。这就是我所说的显式多态。
由于 Car 和Vehicle 中都有 drive() 函数,为了指明调用对象,我们必须使用绝对(而不是相对)引用。我们通过名称显式指定 Vehicle 对象并调用它的 drive() 函数。
但是如果直接执行 Vehicle.drive() ,函数调用中的 this 会被绑定到 Vehicle 对象而不是Car 对象(参见第 2 章),这并不是我们想要的。因此,我们会使用 .call(this) 来确保 drive() 在 Car 对象的上下文中执行。
显示混入模式的另一种变体“寄生继承”,既是显示也是隐式。
// “传统的 JavaScript 类”Vehicle function Vehicle() { this.engines = 1; } Vehicle.prototype.ignition = function() { console.log( "Turning on my engine." ); }; Vehicle.prototype.drive = function() { this.ignition(); console.log( "Steering and moving forward!" ); }; // “寄生类” Car function Car() { // 首先,car 是一个 Vehicle var car = new Vehicle(); // 接着我们对 car 进行定制 car.wheels = 4; // 保存到 Vehicle::drive() 的特殊引用 var vehDrive = car.drive; // 重写 Vehicle::drive() car.drive = function() { vehDrive.call( this ); console.log( "Rolling on all " + this.wheels + " wheels!" ); return car; } var myCar = new Car(); myCar.drive(); // 发动引擎。 // 手握方向盘! // 全速前进!
总的来说,不推荐js模拟类。