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

 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
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模式的更多相关文章

  1. Mixin模式:带实现的协议

    Mixin(织入)模式并不是GOF的<设计模式>归纳中的一种,但是在各种语言以及框架都会发现该模式(或者思想)的一些应用.简单来说,Mixin是带有全部实现或者部分实现的接口,其主要作用是 ...

  2. 什么是Mixin模式:带实现的协议

    Mixin(织入)模式并不是GOF的<设计模式>归纳中的一种,但是在各种语言以及框架都会发现该模式(或者思想)的一些应用.简单来说,Mixin是带有全部实现或者部分实现的接口,其主要作用是 ...

  3. 设计模式之Mixin模式

    介绍 mixin模式就是一些提供能够被一个或者一组子类简单继承功能的类,意在重用其功能.在面向对象的语言中,我们会通过接口继承的方式来实现功能的复用.但是在javascript中,我们没办法通过接口继 ...

  4. mixin模式特点

    mixin模式特点: 1.单一功能, 2.不和基类关联,可以和任意基类组合,基类可以不和mixin关联就可以初始化成功 3.不使用 super() 用法

  5. PythonI/O进阶学习笔记_3.2面向对象编程_python的继承(多继承/super/MRO/抽象基类/mixin模式)

    前言: 本篇相关内容分为3篇多态.继承.封装,这篇为第二篇 继承. 本篇内容围绕 python基础教程这段: 在面向对象编程中,术语对象大致意味着一系列数据(属性)以及一套访问和操作这些数据的方法.使 ...

  6. 【javascript】javascript设计模式mixin模式

    概述: Mixin是JavaScript中用的最普遍的模式,几乎所有流行类库都会有Mixin的实现.任意一个对象的全部或部分属性拷贝到另一个对象上. 一 .混合对象 二 .混合类

  7. 前端框架中 “类mixin” 模式的思考

    "类 mixin" 指的是 Vue 中的 mixin,Regular 中的 implement 使用 Mixin 的目的 首先我们需要知道为什么会有 mixin 的存在? 为了扩展 ...

  8. 关于Python的Mixin模式

    转自:http://www.bjhee.com/python-mixin.html 像C或C++这类语言都支持多重继承,一个子类可以有多个父类,这样的设计常被人诟病.因为继承应该是个”is-a”关系. ...

  9. 【转载】关于Python的Mixin模式

    本博按: mixin是看起来是多继承的一种,但是,这种继承并不作为父类存在,而是增加功能到子类中. 像C或C++这类语言都支持多重继承,一个子类可以有多个父类,这样的设计常被人诟病.因为继承应该是个” ...

随机推荐

  1. 异步编程 In .NET(转载)

    概述 在之前写的一篇关于async和await的前世今生的文章之后,大家似乎在async和await提高网站处理能力方面还有一些疑问,博客园本身也做了不少的尝试.今天我们再来回答一下这个问题,同时我们 ...

  2. Oracle 表空间查询与操作方法

    一.查询篇 1.查询oracle表空间的使用情况 select b.file_id 文件ID,  b.tablespace_name 表空间,  b.file_name 物理文件名,  b.bytes ...

  3. 如何查看oracle表空间是否自动扩展

    select file_name,autoextensible,increment_by from dba_data_files

  4. 在Windows Server 2012启用或关闭Internet Explorer增强的安全配置

    在 Windows Sever 2012 中打开 IE 浏览器时,IE10 会出现[已启用 Internet Explorer 增强的安全配置]的提示信息. 在安全性等级中会设置以[高安全性],如果我 ...

  5. IDEA中修改各个部位的字体大小

    1.菜单栏 Setting -> Appearance&Behavior -> Appearance ->Override default fonts by (not rec ...

  6. Android ListView根据项数的大小自动改变高度

    第一种:按照listview的项数确定高度 ListAdapter listAdapter = listView.getAdapter();      if (listAdapter == null) ...

  7. python的requests模块

    使用python进行接口测试得时候可以使用requests模块,是基于 urllib,采用 Apache2 Licensed 开源协议的 HTTP 库 安装requests是模块 pip instal ...

  8. tesseract-ocr训练方法

    tesseract-ocr有2和3两个版本,不同版本训练方法稍有不同. 第3版本的训练方法官版教程在这里:TrainingTesseract3 第2版的训练方法官版教程在这里:TrainingTess ...

  9. 【转】TCP、UDP数据包大小的限制

    来自:https://blog.csdn.net/caoshangpa/article/details/51530685 1.概述 首先要看TCP/IP协议,涉及到四层:链路层,网络层,传输层,应用层 ...

  10. js跳出for循环

    1 使用普通的for循环 注意foreach使用return或break都无法跳出循环 2 使用every跳出循环, every 方法会遍历数组中的所有元素来判断是否满足条件,如果有一个元素返回fal ...