zoukankan      html  css  js  c++  java
  • 掺合模式(Mixin)

    Mixin是JavaScript中用的最普遍的模式,可以就任意一个对象的全部或部分属性拷贝到另一个对象上。从提供的接口来看,有的是对对象的操作,有的是对类的操作。对类的操作又称为掺元类(Mixin classes)几乎所有流行类库都会有Mixin的实现。

    比如说:

       jQuery的$.extend 操作对象,将其它对象的属性方法拷贝到目标对象。

      RequireJS的私有的mixin 操作对象,将其它对象的属性方法拷贝到目标对象。

      Underscore.js 的 _.extend,把第二个参数起的所有对象都拷贝到第一个参数

    1.掺合对象 (Mixin object)

    先看最简单的mixin实现

    function mixin(dest, src) {
        for (var key in src) {
            dest[key] = src[key]
        }
    }
    
    //使用下
    
    var person = {name: 'yudi', age: 24}
    var obj = {}
    mixin(obj, person)
    console.log(obj) // {name: 'yudi', age: 24}

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

    function mixin(dest, src) {
        for (var key in src) {
            if (!dest[key]) {
                dest[key] = src[key]
            }
        }
    }
    //使用
    var person = {name: 'yudi', age: 24}
    var obj = {name: 'rain'}
    mixin(obj, person)
    console.log(obj) // Object { name="yudi", age=24}

    当然,你可以提供更强大,灵活的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}
    

    2.掺和类(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()}
    

      

  • 相关阅读:
    结构层HTML + 表现层CSS
    移动端:项目实战
    移动端:开发技巧
    两个对象数组,把其中相同的name的before相加,不同的对象添加到数组里
    js中遍历数组和遍历对象
    css学习笔记一
    Angular2父子组件数据传递之@ViewChild获取子组件详解
    css知识点总结
    js中的apply,call,arguments,callee,caller详解
    javascript中的排序
  • 原文地址:https://www.cnblogs.com/rainheader/p/4574919.html
Copyright © 2011-2022 走看看