如何在 javascript 中实现特征?
javascript中的特征
IT技术
javascript
prototype
traits
                    2021-02-23 05:34:12
                
                    
                
            
        3个回答
            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]
有不同的方法,同时也有生产就绪的库。
Mixin 是跨类层次结构的最古老的代码重用形式。它们需要按线性顺序组合,因为 Mixins 的概念不包括/识别冲突解决功能。
Traits 是细粒度的代码重用单元,也适用于类级别;但它们更加灵活,因为 Traits 必须为方法的组合、排除或别名提供组合运算符。
我确实建议阅读 2 篇论文,这两篇论文都涵盖了针对 Mixins/Traits/Talents 的基于库的纯函数方法。
- 2011 年 5 月由 Angus Croll重新审视 JavaScript Mixins
 - JavaScript 在2014 年 4 月推广面向角色的编程方法(如 Traits 和 Mixins)的众多才能。
 
基于纯函数和委托的 mixin 机制与接下来两个给定示例中提供的一样简单......
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
如果需要已建立和/或生产就绪的库,则应仔细查看
这么久
附录一
另请参阅:
- stackoverflow.com ::如何在 Javascript 中正确使用 mixins
 - stackoverflow.com :: Javascript Traits 模式资源
 
附录二
因为有时我显然在摆弄这件事,所以我不想添加一些最终的想法......
没有太多胶水代码(如上所述)的库不可知方法仅适用于行为重用的非常细粒度的可组合单元。因此,只要不遇到超过 1 或 2 个容易解决的冲突,基于 Angus Croll 的Flight Mixins等模式就是要遵循的路径。
如果涉及到真正的特征,就必须有一个抽象层次。这一层(例如作为某种语法糖提供,如 DSL)需要隐藏复杂性,例如从特征组合特征或在特征应用时间(当特征的行为被应用到对象/类型时)解决冲突的复杂性。
到目前为止,SO 上有 3 个示例,从我的角度来看,它们正是 OP 所要求的……
如何在 javascript 中实现特征?
- stackoverflow.com :: JS 中的组合和混合
 - stackoverflow.com :: ES6 类的 Mixin,用 babel 转译
 - stackoverflow.com ::重构遗留的基于 mixin 的类层次结构
 - stackoverflow.com ::使用类的多重继承