How to use mixins properly in Javascript

前端 未结 4 1172
花落未央
花落未央 2020-11-28 15:13

I am organizing a small enterprise application but would like to be as DRY as possible. As a result, I\'ve been looking at mixin libraries.

I came across this librar

4条回答
  •  栀梦
    栀梦 (楼主)
    2020-11-28 15:39

    please see also:

    • stackoverflow.com :: Traits in javascript
    • stackoverflow.com :: Javascript Traits Pattern Resources

    If it comes to JavaScript and Role based composition approaches like Mixins and Traits, I'm meanwhile very opinionated. I always will point to a library agnostic mix of 2 purely function based patterns - firstly the module pattern and secondly the "Flight Mixin" pattern as it has been rediscovered, named and described by Angus Croll in May 2011. But I also would recommend reading a paper of mine from April 2014.

    • A fresh look at JavaScript Mixins
    • The many talents of JavaScript for generalizing Role Oriented Programming approaches like Traits and Mixins

    Questions

    • 1) What are some real application examples of useful Mixins? (pls no more abstract examples)
    • 2) Do I even need to extend classes or can I just use this library to manage all extensions and mixins?

    Answering your 2 questions ...

    1st) [Observable] probably is one of the most common real world examples for Mixins. But this is not the right place for providing its entire code base. The successively growing examples from the Smart Talents chapter do provide working implementations of a [Queue] factory that in the beginning just uses different Mixins like [Enumerable] and [Allocable] but finally also applies the already mentioned [Observable].

    2nd) Just make use of a module system of your choice or need - CommonJS or AMD. Your factory modules or even instances/objects then do retrieve additional behavior by delegation; thus they actively do call / apply the Mixin or Trait modules.

    finally - shortened example code:

    var Observable_SignalsAndSlots = (function () {
    
      var
        Event = function (target, type) {
    
          this.target = target;
          this.type = type;
        },
    
        EventListener = function (target, type, handler) {
    
          var defaultEvent = new Event(target, type);
    
          this.handleEvent = function (evt) {
            /* ... */
          };
          this.getType = function () {
            return type;
          };
          this.getHandler = function () {
            return handler;
          };
        },
    
        EventTargetMixin = function () {
    
          var eventMap = {};
    
          this.addEventListener = function (type, handler) {
            /* ... */
          };
          this.dispatchEvent = function (evt) {
            /* ... */
          };
        }
      ;
    
      return EventTargetMixin;
    
    }).call(null);
    
    
    var Queue = (function () {
    
      var
        global = this,
    
        Observable  = global.Observable_SignalsAndSlots,
      //Allocable   = global.Allocable,
    
        Queue,
    
        onEnqueue = function (queue, type) {
          queue.dispatchEvent({type: "enqueue", item: type});
        },
        onDequeue = function (queue, type) {
          queue.dispatchEvent({type: "dequeue", item: type});
        },
        onEmpty = function (queue) {
          queue.dispatchEvent("empty");
        }
      ;
    
      Queue = function () { // implementing the [Queue] Constructor.
        var
          queue = this,
          list = []
        ;
        queue.enqueue = function (type) {
    
          list.push(type);
          onEnqueue(queue, type);
    
          return type;
        };
        queue.dequeue = function () {
    
          var type = list.shift();
          onDequeue(queue, type);
    
          (list.length || onEmpty(queue));
    
          return type;
        };
        Observable.call(queue);
      //Allocable.call(queue, list);
      };
    
      return Queue;
    
    }).call(null);
    
    
    var q = new Queue;
    
    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);});
    
    console.log("q.addEventListener : ", q.addEventListener);
    console.log("q.dispatchEvent : ", q.dispatchEvent);
    
    console.log("q.enqueue('the') ... ", q.enqueue('the'));     // "enqueue" Object {type: "enqueue", item: "the", target: Queue}
    console.log("q.enqueue('quick') ... ", q.enqueue('quick')); // "enqueue" Object {type: "enqueue", item: "quick", target: Queue}
    console.log("q.enqueue('brown') ... ", q.enqueue('brown')); // "enqueue" Object {type: "enqueue", item: "brown", target: Queue}
    console.log("q.enqueue('fox') ... ", q.enqueue('fox'));     // "enqueue" Object {type: "enqueue", item: "fox", target: Queue}
    
    console.log("q.dequeue() ... ", q.dequeue()); // "dequeue" Object {type: "dequeue", item: "the", target: Queue}
    console.log("q.dequeue() ... ", q.dequeue()); // "dequeue" Object {type: "dequeue", item: "quick", target: Queue}
    console.log("q.dequeue() ... ", q.dequeue()); // "dequeue" Object {type: "dequeue", item: "brown", target: Queue}
    console.log("q.dequeue() ... ", q.dequeue()); // "dequeue" Object {type: "dequeue", item: "fox", target: Queue}
                                                  // "empty"   Object {target: Queue, type: "empty"}
    console.log("q.dequeue() ... ", q.dequeue()); // "dequeue" Object {type: "dequeue", item: undefined, target: Queue}
                                                  // "empty"   Object {target: Queue, type: "empty"}
    .as-console-wrapper { max-height: 100%!important; top: 0; }

提交回复
热议问题