如何在Javascript中正确使用mixin

如何在Javascript中正确使用mixin,javascript,dry,mixins,Javascript,Dry,Mixins,我正在组织一个小型企业应用程序,但希望尽可能干燥。因此,我一直在研究mixin库 我遇到了这个问题,认为它可能是一个不错的选择,因为它允许您在运行时进行混合。此外,我可以只使用一个基类(BaseView)作为例子,并将其混合使用 问题 有用的mixin的一些实际应用示例是什么?(请不要再有抽象的例子) 我甚至需要扩展类,还是可以使用这个库来管理所有扩展和混合 mixin只是一个不同的概念,即如何组织代码和继承。当然,您可以将它与使用经典或原型继承相结合,但也可以说它是独立工作的 例如,与创建“委

我正在组织一个小型企业应用程序,但希望尽可能干燥。因此,我一直在研究mixin库

我遇到了这个问题,认为它可能是一个不错的选择,因为它允许您在运行时进行混合。此外,我可以只使用一个基类(BaseView)作为例子,并将其混合使用

问题

  • 有用的mixin的一些实际应用示例是什么?(请不要再有抽象的例子)
  • 我甚至需要扩展类,还是可以使用这个库来管理所有扩展和混合
  • mixin只是一个不同的概念,即如何组织代码和继承。当然,您可以将它与使用经典或原型继承相结合,但也可以说它是独立工作的

    例如,与创建“委托的”对象属性/查找(如原型继承)不同,我们将从多个其他对象中真正“形成”新的独立对象。这有时也被称为“多重继承”,单靠Javascripts原型继承是不容易实现的

    例如:

    var pianist = {
       play: function() {}
    };
    
    var programmner: {
       code: function() {}
    };
    
    现在我们可以创建另一个对象,比如

    这个伪
    extend
    方法看起来像(ES5):



    我实际上没有正确回答你的问题,但我觉得你的问题没有真正的答案。它就像您要使用它一样真实,实际上没有“特定于应用程序”的用例。

    我们使用一个名为(mixins…get It?)的mixin库。它专门用于主干应用程序,但非常好

    我们所做的工作比我在这里描述的要好。

    另请参见:

    • stackoverflow.com::
    • stackoverflow.com::
    如果涉及到JavaScript和基于角色的合成方法,比如mixin和Traits,我同时非常固执己见。我总是会指出两种纯粹基于函数的模式的库不可知混合——第一种是模块模式,第二种是安格斯·克罗尔在2011年5月重新发现、命名和描述的“Flight Mixin”模式。但我也建议读一篇2014年4月的论文

    问题

    • 1) 有用的mixin的一些实际应用示例是什么?(请不要再有抽象的例子)
    • 2) 我甚至需要扩展类,还是可以使用这个库来管理所有扩展和混合
    回答你的两个问题

    第一)
    [Observable]
    可能是混音最常见的现实例子之一。但这不是提供整个代码库的正确位置。来自do的连续增长的示例提供了一个
    [Queue]
    工厂的工作实现,该工厂一开始只使用不同的混合,如
    [Enumerable]
    [Allocable]
    ,但最后还应用了前面提到的
    [observatable]

    2)只需使用您选择或需要的模块系统-。然后,您的工厂模块甚至实例/对象通过委托检索其他行为;因此,他们主动调用Mixin或Trait模块

    最后-缩短示例代码:

    var可观测信号和插槽=(函数(){
    变量
    事件=功能(目标,类型){
    this.target=目标;
    this.type=type;
    },
    EventListener=函数(目标、类型、处理程序){
    var defaultEvent=新事件(目标,类型);
    this.handleEvent=函数(evt){
    /* ... */
    };
    this.getType=函数(){
    返回类型;
    };
    this.getHandler=函数(){
    返回处理程序;
    };
    },
    EventTargetMixin=函数(){
    var eventMap={};
    this.addEventListener=函数(类型,处理程序){
    /* ... */
    };
    this.dispatchEvent=函数(evt){
    /* ... */
    };
    }
    ;
    返回EventTargetMixin;
    }).call(空);
    变量队列=(函数(){
    变量
    全局=这个,
    可观测=全局。可观测信号和插槽,
    //Allocable=global.Allocable,
    队列
    ONNEQUEUE=函数(队列,类型){
    dispatchEvent({type:“enqueue”,item:type});
    },
    onDequeue=函数(队列,类型){
    dispatchEvent({type:“dequeue”,item:type});
    },
    onEmpty=函数(队列){
    queue.dispatchEvent(“空”);
    }
    ;
    Queue=函数(){//实现[Queue]构造函数。
    变量
    队列=此,
    列表=[]
    ;
    queue.enqueue=函数(类型){
    列表、推送(类型);
    队列(队列,类型);
    返回类型;
    };
    queue.dequeue=函数(){
    var type=list.shift();
    onDequeue(队列,类型);
    (list.length | | onEmpty(queue));
    返回类型;
    };
    可观察呼叫(队列);
    //可分配呼叫(队列、列表);
    };
    返回队列;
    }).call(空);
    var q=新队列;
    q、 addEventListener(“enqueue”,function(evt){console.log(“enqueue,evt);});
    q、 addEventListener(“dequeue”,function(evt){console.log(“dequeue”,evt);});
    q、 addEventListener(“empty”,function(evt){console.log(“empty”,evt);});
    log(“q.addEventListener:”,q.addEventListener);
    console.log(“q.dispatchEvent:,q.dispatchEvent”);
    console.log(“q.enqueue('the')…”,q.enqueue('the'));//“排队”对象{type:“排队”,item:“the”,target:Queue}
    console.log(“q.enqueue('quick')…”,q.enqueue('quick'));//“排队”对象{类型:“排队”,项目:“快速”,目标:队列}
    console.log(“q.enqueue('brown')…”,q.enqueue('brown'));//“排队”对象{类型:“排队”,项目:“布朗”,目标:队列}
    console.log(“q.enqueue('fox')…”,q.enqueue('fox'));//“排队”对象{类型:“排队”,项目:“福克斯”,目标:队列}
    console.log(“q.dequeue()…”,q.dequeue());//“出列”对象{type:“出列”,item:“the”,target:Queue}
    console.lo
    
    var Jim = Object.create( null ); // create a fully self-defining object
    
    extend( Jim, pianist );
    extend( Jim, programmer );
    
    function extend( target, source ) {
        Object.getOwnPropertyNames( source ).forEach(function( key ) {
            Object.defineProperty( target, key, Object.getOwnPropertyDescriptor(source, key)) });
    
        return target
    }
    
    var speakable = {
        speak: function(){ return this.name + " speaks" }
    }
    
    var flyable = {
        fly: function(){ return this.name + " flies" }
    }
    
    var MallardDuck = function(name){
      this.name = name;
    }
    
    var Parrot = function(name){
      this.name = name;
    }
    
    $.extend(MallardDuck.prototype, speakable, flyable);
    $.extend(Parrot.prototype, speakable, flyable);
    
    var duck = new MallardDuck('Bob');
    var parrot = new Parrot('Jane');
    console.log(duck.speak());
    console.log(parrot.speak());
    
    function extend(target){
      // if no mixin objects are provided, then return out of function
      if(!arguments[1])
        return;
    
      // the first argument is the target object we want to mix behavior into, so we start our loop at index 1
      for(var i = 1; j = arguments.length; i < j; i++) {
        // grab the singleton object to mixin into target
        var source = arguments[i];
    
        for(var propr in source) {
          // ensure we do not override a property that target already has
          if(!target[prop] && source.hasOwnProperty(prop)){
            target[prop] = source[prop];
          }
        }
      }
    }
    
    const speakable = {
        speak: function(){ return `${this.name} speaks`; }
    }
    
    const flyable = {
        fly: function(){ return `${this.name} flies` }
    }
    
    
    class MallardDuck {
      constructor(name) {
        this.name = name;
        Object.assign(MallardDuck.prototype, speakable); // add the mixin to prototype chain. Alternatively, use 'this' to add directly to the new object being created
      }
    }
    
    class Parrot {
      constructor(name) {
        this.name = name;
        Object.assign(Parrot.prototype, speakable); // add the mixin to prototype chain. Alternatively, use 'this' to add directly to the new object being created
      }
    }
    
    const duck = new MallardDuck('Mallard Duck');
    const parrot = new Parrot('Parrot');
    console.log(duck.speak());
    console.log(parrot.speak());