【问题标题】:Traits in javascript [closed]javascript中的特征[关闭]
【发布时间】:2009-12-30 06:46:41
【问题描述】:

如何在 javascript 中实现特征?

【问题讨论】:

    标签: javascript prototype traits


    【解决方案1】:
    function Trait (methods) {
      this.traits = [methods];
    };
    
    Trait.prototype = {
        constructor: Trait
    
      , uses: function (trait) {
          this.traits = this.traits.concat (trait.traits);
          return this;
        }
    
      , useBy: function (obj) {
          for (var i = 0; i < this.traits.length; ++i) {
            var methods = this.traits [i];
            for (var prop in methods) {
              if (methods.hasOwnProperty (prop)) {
                obj [prop] = obj [prop] || methods [prop];
              }
            }
          }
        }
    };
    
    Trait.unimplemented = function (obj, traitName) {
      if (obj === undefined || traitName === undefined) {
        throw new Error ("Unimplemented trait property.");
      }
      throw new Error (traitName + " is not implemented for " + obj);
    };
    

    例子:

    var TEq = new Trait ({
        equalTo: function (x) {
          Trait.unimplemented (this, "equalTo");
        }
    
      , notEqualTo: function (x) {
          return !this.equalTo (x);
        }
    });
    
    var TOrd = new Trait ({
        lessThan: function (x) {
          Trait.unimplemented (this, "lessThan");
        }
    
      , greaterThan: function (x) {
          return !this.lessThanOrEqualTo (x);
        }
    
      , lessThanOrEqualTo: function (x) {
          return this.lessThan (x) || this.equalTo (x);
        }
    
      , greaterThanOrEqualTo: function (x) {
          return !this.lessThan (x);
        }
    }).uses (TEq);
    
    
    function Rational (numerator, denominator) {
      if (denominator < 0) {
        numerator *= -1;
        denominator *= -1;
      }
      this.numerator = numerator;
      this.denominator = denominator;
    }
    
    Rational.prototype = {
        constructor: Rational
    
      , equalTo: function (q) {
          return this.numerator * q.numerator === this.denominator * q.denominator;
        }
    
      , lessThan: function (q) {
          return this.numerator * q.denominator < q.numerator * this.denominator;
        }
    };
    
    TOrd.useBy (Rational.prototype);
    
    var x = new Rational (1, 5);
    var y = new Rational (1, 2);
    
    [x.notEqualTo (y), x.lessThan (y)]; // [true, true]
    

    【讨论】:

    • 将 TOrd.useBy 移到 Rational 构造函数之外,改为作用于原型。
    • 太棒了!好古老的语言!好的新思路
    • 遗憾的是没有逐行解释。
    【解决方案2】:

    有不同的方法,同时生产就绪的库也是如此。

    Mixins 是跨类层次结构的最古老的代码重用形式。它们需要按线性顺序组合,因为 Mixins 的概念不涵盖/识别冲突解决功能。

    特征是代码重用的细粒度单元,也适用于类级别;但它们更灵活,因为 Traits 必须为方法的组合、排除或别名提供组合运算符。

    我确实建议阅读 2 篇论文,这两篇论文都涵盖了针对 Mixins/Traits/Talents 的与库无关的纯函数方法。

    1. A fresh look at JavaScript Mixins 来自 2011 年 5 月的 Angus Croll
    2. The many talents of JavaScript for generalizing Role Oriented Programming approaches like Traits and Mixins 自 2014 年 4 月起。

    基于纯函数和委托的 mixin 机制与接下来的 2 个给定示例一样简单......

    var Enumerable_first = function () {
      this.first = function () {
        return this[0];
      };
    };
    var list = ["foo", "bar", "baz"];
    
    console.log("(typeof list.first)", (typeof list.first)); // "undefined"
    
    Enumerable_first.call(list); // explicit delegation
    
    console.log("list.first()", list.first()); // "foo"
    

    ...第一个示例在“实例”级别执行,第二个示例覆盖“类”级别...

    var Enumerable_first_last = function () {
      this.first = function () {
        return this[0];
      };
      this.last = function () {
        return this[this.length - 1];
      };
    };
    console.log("(typeof list.first)", (typeof list.first));  // "function"   // as expected
    console.log("(typeof list.last)", (typeof list.last));    // "undefined"  // of course
    
    Enumerable_first_last.call(Array.prototype);  // applying behavior to [Array.prototype]
    
    console.log("list.last()", list.last());      // "baz"  // due to delegation automatism
    

    如果需要已建立和/或生产就绪的库,则应仔细查看

    1. traits.js
    2. CocktailJS

    这么久

    附录一

    另请参阅:

    附录二

    由于我不时地在处理这件事,所以我不想在这件事上添加一些最后的想法......

    没有太多胶水代码(如上所述)的库无关方法仅适用于行为重用的非常细粒度的可组合单元。因此,只要不遇到超过 1 或 2 个易于解决的冲突,基于例如Angus Croll 的 Flight Mixins 是我们应该遵循的路径。

    如果涉及到真正的特征,则必须有一个抽象级别。该层(例如,作为某种语法糖(如 DSL)提供)需要隐藏复杂性,例如从特征组合特征或在特征应用时解决冲突(当特征的行为应用于对象/类型时)。

    到目前为止,SO 有 3 个示例,从我的角度来看,它们提供了 OP 确实要求的内容……

    如何在 javascript 中实现特征?

    【讨论】:

      【解决方案3】:

      我强烈建议您查看trait.js 库。他们也有一篇关于一般模式及其具体实现的很好的文章。我最近在我的项目中内置了它,它就像一个魅力。

      【讨论】:

        猜你喜欢
        • 2017-01-08
        • 2021-03-25
        • 1970-01-01
        • 2011-08-25
        • 1970-01-01
        • 2013-09-01
        • 1970-01-01
        • 1970-01-01
        • 2017-01-01
        相关资源
        最近更新 更多