前言:这一章我们来介绍一下 Mixin 混入模式,我们可以将 Mixin 看做一种扩展收集功能的方式。它可以为任意数量的对象实例定义属性,我们可以利用这一点来促进函数复用。
Mixin 模式的目的 Mixin 允许对象通过较低的复杂度借用( 或继承 )功能。该模式与 Javascipt 的对象原型配合地非常好,它为我们提供了一个相当灵活的方式,从不只一个 Mixin 中分享功能,但实际上很多功能是通过多重继承得到的。他们可以被视为具有可以在很多其他对象原型中轻松共享属性和方法的对象。
借助 Underscore 实现 Mixin 的一个例子 下面我们首先在一个标准对象字面量中定义一个包含实用函数的 Mixin
1 2 3 4 5 6 7 8 9 10 11 var myMixins = { moveUp: function ( ) { console .log('move up' ); }, moveDown: function ( ) { console .log('move down' ); }, stop: function ( ) { console .log('stop' ); } };
然后我们可以使用诸如 underscore 中的 _.extend 方法轻松扩展现有构造函数的原型,以将上述行为包含进来
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 function carAnimator ( ) { this .moveLeft = function ( ) { console .log('moveLeft' ); } } function personAnimator ( ) { this .moveRandomly = function ( ) { console .log('moveRandomly' ); } } _.extend(carAnimator.prototype, myMixins); _.extend(personAnimator.prototype, myMixins); var myAnimator = new carAnimator();myAnimator.moveLeft(); myAnimator.moveDown(); myAnimator.stop();
正如上面的例子,这允许我们以通用的方式轻松 “混入” 对象构造函数。
脱离 Underscore 实现 Mixin 的一个例子 在下面的这个例子中,我们不借助 Underscore 来实现一个 Mixin 的例子。在下面的例子中,我们有 Car 和 Mixin 两个构造函数,我们要做的是扩展 Car,以便它可以继承 Mixin 中定义的特定方法 ( 在本例中为 driveForward 和 driveBackward ) ,代码如下:
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 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 var Car = function (settings ) { this .model = settings.model || "no model provided" ; this .color = settings.color || "no color provided" ; }; var Mixin = function ( ) {}; Mixin.prototype = { driveForward: function ( ) { console .log('drive forward' ); }, driveBackward: function ( ) { console .log('drive backward' ); }, driveSideways: function ( ) { console .log('drive sideways' ) } }; function augment (receivingClass, givingClass ) { if (arguments [2 ]) { for (var i = 0 , len = arguments .length; i < len; i++) { receivingClass.prototype[arguments [i]] = givingClass.prototype[arguments [i]]; } } else { for (var methodName in givingClass.prototype) { if (!receivingClass.prototype.hasOwnProperty(methodName)) { receivingClass.prototype[methodName] = givingClass.prototype[methodName]; } } } } augment(Car, Mixin, "driveForward" , "driveBackward" ); var myCar = new Car({ model: "Ford Escort" , color: "blue" }); myCar.driveForward(); myCar.driveBackward(); augment(Car, Mixin); var mySportsCar = new Car({ model: "Porsche" , color: "red" }); mySportsCar.driveSideways();
Mixin 模式的优点 Mixin 模式有助于减少系统中重复的功能,增加函数复用。当一个应用程序可能需要在各种对象实例中共享行为时,我们可以通过在 Mixin 中维持这种贡献功能并专注于仅实现系统中真正不同的功能,来轻松避免冗余
Mixin 的缺点 Mixin 可能导致原型污染和函数起源方面的不确定性。但是,话说回来,完整夯实的文档有助于将 Mixin 模式的缺点降低到最小,编写文档的时候需要多加注意。