JavaScript 中的特征

发布于 2024-08-16 11:52:27 字数 1702 浏览 5 评论 0原文

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

巾帼英雄 2024-08-23 11:52:27
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]
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);
};

Example:

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]
锦欢 2024-08-23 11:52:27

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

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

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

我确实建议阅读两篇论文,它们都涵盖了与库无关的基于纯函数的 Mixins / Traits / Talents 方法。

  1. 重新审视 JavaScript Mixins作者:Angus Croll,2011 年 5 月
  2. JavaScript 的众多才华,用于概括 2014 年 4 月的 Traits 和 Mixins 等面向角色的编程方法

纯函数基于委托的 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 中实现特征?

There are different approaches and in the meantime production ready libraries as well.

Mixins are the oldest form of code reuse across class hierarchies. They need to be composed in linear order since the concept of Mixins does not cover/recognize conflict resolution functionality.

Traits are fine grained units of code reuse that work on class level too; but they are more flexible since Traits have to provide composition operators for combination, exclusion or aliasing of methods.

I do recommend reading 2 papers both are covering a library agnostic pure function based approach for Mixins / Traits / Talents.

  1. A fresh look at JavaScript Mixins by Angus Croll from May 2011
  2. The many talents of JavaScript for generalizing Role Oriented Programming approaches like Traits and Mixins from April 2014.

The pure function and delegation based mixin mechanics is as straightforward as provided with the next 2 given examples ...

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"

... with the first example acting at "instance" level and the second one covering "class" level ...

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

If one is in need for established and/or production ready libraries one should have a closer look on

  1. traits.js
  2. CocktailJS

so long

Appendix I

please see also:

Appendix II

Since from time to time I'm apparently fiddle with this matter I wan't to add some final thoughts to it ...

The library agnostic approach without too much glue code (as mentioned above) does work only for very fine grained composable units of behavioral reuse. Thus, as long as one does not run into more than 1 or 2 easily resolvable conflicts, patterns based on e.g. Angus Croll's Flight Mixins are the path to follow.

If it comes to real traits, there has to be an abstraction level to it. This layer (e.g. provided as some sort of syntactic sugar like a DSL) needs to hide the complexity e.g. of composing traits from traits or of conflict resolution at a traits apply time (when a trait's behavior gets applied to an object/type).

By now there are 3 examples at SO that from my perspective provide exactly what the OP did ask for …

How can I implement traits in javascript ?

等待圉鍢 2024-08-23 11:52:27

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

I seriously recommend you to checkout the trait.js library. They also have quite a good article about the general pattern as well as their concrete implementation. I have recently built in into my project and it works like a charm.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文