`
zhouyrt
  • 浏览: 1162625 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

掺合模式(Mixin)

 
阅读更多

Mixin是JavaScript中用的最普遍的模式,几乎所有流行类库都会有Mixin的实现。

Mixin是掺合,混合,糅合的意思,即可以就任意一个对象的全部或部分属性拷贝到另一个对象上。

从提供的接口来看,有的是对对象的操作,有的是对类的操作。对类的操作又称为掺元类(Mixin classes)

 

一、掺合对象 (Mixin object)

先看最简单的mixin实现

function mixin(dest, src) {
    for (var key in src) {
        dest[key] = src[key]
    }
}

使用下

var person = {name: 'John', age: 29}
var obj = {}
mixin(obj, person)
console.log(obj) // {name: 'John', age: 29}

可看到,已经将person的所有属性拷贝到obj上了。 有个缺点,如果obj上已经有了name: 'Jack',那么会被person覆盖。因此需要加个判断,如果dest上已经存在了,就不拷贝。

function mixin(dest, src) {
    for (var key in src) {
        if (!dest[key]) {
            dest[key] = src[key]
        }
    }
}
var person = {name: 'John', age: 29}
var obj = {name: 'Jack'}
mixin(obj, person)
console.log(obj) // Object { name="Jack", age=29}

 

当然,你可以提供更强大,灵活的Mixin,比如可以将任意多个对象掺合到目标对象

function mixin(dest /*, Any number of objects */) {
    var sources = Array.prototype.slice.call(arguments, 1)
    for (var i=0; i<sources.length; i++) {
        var src = sources[i]
        for (var key in src) {
            if (!dest[key]) {
                dest[key] = src[key]
            }
        }   
    }
}
var person = {name: 'John', age: 29, toString: function(){return 'aa'}}
var permission = {open: 1}
var obj = {name: 'Jack'}
mixin(obj, person, permission)
console.log(obj) // Object { name="Jack", age=29, open=1}

以下类库都是对对象的掺合

  • jQuery的$.extend 操作对象,将其它对象的属性方法拷贝到目标对象。
  • RequireJS的私有的mixin 操作对象,将其它对象的属性方法拷贝到目标对象。
  • ExtJS的Ext.apply 也是操作对象,它还提供了一个defaults参数。
  • Underscore.js 的 _.extend,把第二个参数起的所有对象都拷贝到第一个参数

 

二、掺和类(Mixin Classes)

有的翻译过来叫做掺元类,它是一种不需要用到严格的继承就可以复用代码的一种技术。如果多个类想用到某个类的某个方法,可以通过扩充这些类的原型已达到共享该方法。比如先创建一个包含各种通用方法的类,然后让其它类扩充于它。这个包含通用方法的类就叫掺元类。多数时候它不会直接实例化或调用,而是作为其它类的模板用于扩充。

先看最简单的实现

// 工具方法,实现mixin
function augment(destClass, srcClass) {
    var destProto = destClass.prototype
    var srcProto  = srcClass.prototype
    for (var method in srcProto) {
        if (!destProto[method]) {
            destProto[method] = srcProto[method]
        }
    }
}
 
function Person() {} // 具有两个方法的类,用于mixin
Person.prototype.getName = function() {}
Person.prototype.getAge  = function() {}
 
function Student() {} // 没有任何方法的类
 
augment(Student, Person) // 调用,拷贝
 
var s1 = new Student()
console.log(s1) // Student { getName=function(), getAge=function()}

工具函数augment接受两个参数,都是函数类型(类),第一个类会从第二个类的原型上继承其方法。即使用Person类扩充了Student类。

我们知道,某些语言如C++/Python允许子类继承多个父类,但在JavaScript中是不允许的,因为一个构造器只有一个原型对象,不过这可以通过多个掺元类的方式实现扩充,这实际是一种变相多继承的实现。和mixin方法类似,修改下augment方法。

function augment(destClass, /*, Any number of classes */) {
    var classes = Array.prototype.slice.call(arguments, 1)
    for (var i=0; i<classes.length; i++) {
        var srcClass = classes[i]
        var srcProto  = srcClass.prototype
        var destProto = destClass.prototype     
        for (var method in srcProto) {
            if (!destProto[method]) {
                destProto[method] = srcProto[method]
            }
        }       
    }
}

这样就实现了多继承。

 

 

有时不想继承所有的方法,指向拷贝指定的方法,增加一个参数methods

function augment(destClass, srcClass, methods) {
    var srcProto  = srcClass.prototype
    var destProto = destClass.prototype     
    for (var i=0; i<methods.length; i++) {
        var method = methods[i]
        if (!destProto[method]) {
            destProto[method] = srcProto[method]
        }
    }
}
function Person() {}
Person.prototype.getName = function() {}
Person.prototype.setName  = function() {}
Person.prototype.getAge  = function() {}
Person.prototype.setAge  = function() {}
 
function Student() {}
 
augment(Student, Person, ['getName', 'setName'])
var s1 = new Student()
console.log(s1) // Student { getName=function(), setName=function()}

 

Backbone是广泛使用掺元类的库

首先,Backbone库自身就采用Mixin classes方式组织,如Backbone.Events是最底层的掺元类,它的方法(on/off/trigger...)都被Backbone.Model/Backbone.Collection/Backbone.View等继承。代码片段如下

_.extend(Model.prototype, Events, {
    ...
})
_.extend(Collection.prototype, Events, {
    ...
})
_.extend(View.prototype, Events, {
    ...
})

它这里使用_.extend来扩充Model,Collection,View的原型,把Events的方法都拷贝到原型。即Event就是一个掺元类(虽然被实现为一个对象)

 

其次,我们使用Backbone开发时,你写的模型会用Backbone.Model去扩充,视图会用Backbone.View去扩充。如

var MyModel = Backbone.Model.extend({
    instanceProp: xx
},{
    classProp: yy
})
 
var MyView = Backbone.Model.extend({
    instanceProp: xx
},{
    classProp: yy
})

  

这时,Backbone.Model/Backbone.View等就是掺元类了。当然,你还可以把underscore当做掺元对象,因为Backbone的很多类都继承了_.extend方法,如Backbone.Events/Backbone.Model等。

 

 

分享到:
评论

相关推荐

    Mixin,MIXIN是使用ASM的Java的特性/混合框架.zip

    Mixin框架的设计理念是基于面向切面编程(AOP)思想,但与传统的AOP实现不同,如Spring AOP,Mixin不使用代理模式。它直接将混入(Mixin)类的功能注入到目标类中,使得目标类就像直接拥有这些功能一样。这种方法可以...

    小程序mixin混入Page选项合并

    `mixin` 是 JavaScript 中的一个设计模式,它允许我们将一组相关的方法或属性组合在一起,形成一个混入对象。在微信小程序中,`mixin` 可以包含数据(data)、生命周期方法、事件处理函数等,可以被多个页面或组件...

    ymixin是来自阅文前端团队的CSS预处理器mixin库

    【ymixin:阅文前端团队的CSS预处理器mixin库详解】 在前端开发中,CSS预处理器如Sass、Less和Stylus等已经成为提升样式编写效率和代码可维护性的必备工具。ymixin,作为阅文前端团队打造的一款CSS预处理器mixin库...

    mixin白皮书

    mixin是一个闪电交易快速的点点对的数字交道项目,它拥有非常好的技术栈。

    A Swift mixin for UITableViewCells and UICollectionViewCells.zip

    A Swift mixin for UITableViewCells and UICollectionViewCells.zip,A Swift mixin for reusing views easily and in a type-safe way (UITableViewCells, UICollectionViewCells, custom UIViews, ViewControllers...

    动态代理的5模式使用示例和Mixin模式

    本文简单描述了5种代理生成模式和1种Mixin模式,最后给出一个示例。 代码如下:public interface IPlayable { void Play(); }  public class Animal : IPlayable { public virtual void Play() { 

    modernizr-mixin, 在Sass中,针对测试的简单而全面的mixin.zip

    modernizr-mixin, 在Sass中,针对测试的简单而全面的mixin hardwarebutton混合 一种简单的DRYier测试方法,在Sass中更快更。安装要求 ruby 3.4或者 LibSass 3.2Libsass警告:在 Libsass 3.2.3中有一个已知 Bug,它...

    使用Mixin设计模式进行Python编程的方法讲解

    Mixin模式是一种在python里经常使用的模式,适当合理的应用能够达到复用代码,合理组织代码结构的目的。 Python的Mixin模式可以通过多继承的方式来实现, 举例来说,我们自定义一个简单的具有嵌套结构的数据容器: ...

    forge-mixin-example:在Minecraft Forge 1.12.2中使用Mixin的示例

    而Mixin是Java编程语言中的一种强大的代码注入框架,常用于Minecraft模组开发,它允许开发者无侵入地修改游戏的内部行为,而无需直接继承或修改原代码。本示例项目"forge-mixin-example"就是针对Minecraft Forge ...

    前端大厂最新面试题-mixin.docx

    Vue 中的 Mixin 及其应用场景 在 Vue 中,Mixin 是一种提供了方法实现的类,其他类可以访问 Mixin 类的方法而不必成为其子类。Mixin 类通常作为功能模块使用,在需要该功能时“混入”,有利于代码复用又避免了多...

    mixin:Mix Mixin TEE-BFT-DAG网络参考实现

    混合Mixin BFT-DAG网络参考实现,受信任的执行环境尚未集成到此存储库中。开始使用按照此指南安装golang并设置GOPATH 。 $ git clone https://github.com/MixinNetwork/mixin.git$ cd mixin$ go build mixin命令既是...

    mixin:JavaScript中的原型mixin构造函数

    Mixin.js Mixin是将功能重复混合到原型JavaScript类中的简便方法。 它会自动处理覆盖的原型方法和调用构造函数的组合。 而且,它将通知已混合到另一个类中的混合构造函数。 这可用于构造依赖的混合层次结构。 安装 ...

    JS自定义混合Mixin函数示例

    Mixin是将一个对象的属性和方法混入到另一个对象中的一种模式,它允许我们把一个类的某些功能复制到另一个类中,而无需建立真正的继承关系。 首先,我们看到一个augment函数的实现,它的目的是为了能够将一个类...

    前端开源库-react-addons-pure-render-mixin

    "react-addons-pure-render-mixin"是React的一个官方加载项,它提供了一个优化性能的策略,特别是在处理大型复杂应用时。 标题中的“react-addons-pure-render-mixin”是React的一个关键特性,用于帮助开发者实现更...

    react-validate-mixin:react validation mixin

    #react-validate-mixin npm install react-validate-mixin或者 bower install react-validate-mixin##例子 var validate = require ( 'react-validate-mixin' ) ;var Compoent = React . createClass ( { mixins ...

    docker-compose-mixin:用于docker-compose CLI的porter mixin

    面向Porter的Docker Compose Mixin 这是Porter的一个混合模块,提供了Docker Compose(docker-compose)CLI。混合声明要在捆绑包中使用此mixin,请这样声明: mixins :- docker-compose必需的扩展名要声明运行该包...

    mixin_java_sdk:Mixin Client Java SDK

    Mixin Client Java SDK这里是 Mixin Client Java SDK,其它语言的 Mixin SDK:NodeJS:Go:Python:更多 Mixin 开发资源:mixin_dev_resource:MiXin_Player:Java SDK v0.2当前版本 v0.2,主要功能是 Mixin 机器人:...

    19-Mixin混入.js

    19-Mixin混入

    19-Mixin混入.ts

    19-Mixin混入

Global site tag (gtag.js) - Google Analytics