JS中的组合和混合 [英] Compostions and mixins in JS

查看:125
本文介绍了JS中的组合和混合的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在作曲 mixin 时遇到了一些麻烦。
例如,让我们假设我们有一个AHero和Hero1对象。
所有英雄都可以移动,所以AHero.move()是一个东西。
现在,在开发的那一刻,我想添加昏迷和beStunned的可能性。所以我创建了一个看起来像这样的新对象(称为stunTrait):

I got some trouble with compostions and mixin. For examples, lets imagine that we have a AHero and Hero1 object. All heroes can move, so AHero.move() is a thing. And now, at a moment of the dev, I want to add the possibility to stun and beStunned. So I make a new object that look like this ( called stunTrait) :

{
stunned : false,
stun(),
beStun,
}

我决定让英雄们感到震惊和震惊。所以我做了一个混音:
类AHero扩展了stunTrait(超类)。

And I decide to give to possiblity to heroes to stun and beStunned. So I do a mixin : class AHero extends stunTrait(superclass).

现在我想要一个震惊的英雄无法移动。
所以在Ahero:

Now I want that a stunned hero can not move. So in Ahero :

move(){
if(this.stunned) return;
...
}

后来我发现晕眩是一个坏主意所以我决定停止实施stunTrait。现在我必须在我的Ahero课堂上找到所有令人震惊的事情,这有时会很难,如果孩子们用这些眩晕的东西做其他事情,那就更难了。

Later I find out stun was a bad idea, so I decide to stop implementing the stunTrait. And now I must find all stunned things in my Ahero class, and this can be sometimes hard, and even harder if child class did some other things with this stun stuff.

有没有办法避免这种情况?更好的设计?

Is there a way to avoid that ? A better design ?

class Object{
  constructor(x,y){
    this.x = x
    this.y = y
  }
}

class AHero extends stunTrait(Object){
  constructor(x,y,moveSpeed){
    this.moveSpeed = moveSpeed;
  }

  move(){
    super.move();
    this.speed = moveSpeed;
  }
}

class hero1 extends AHero{
  constructor(x,y,moveSpeed){ }
}

let stunTrait = function(object){
  return class extends object{
    constructor(...args) {
      super(...args);

      this.stunned = false;
    }

    move(){
      if(this.stunned) this.speed = 0;
    }
  }
}

let hero = new hero1(40, 50, 100);
hero.stunned = true;
hero.move();
// This work, bcs AHero.move() is called before stunTrait.move()
// but if for some reason, I decide that only hero1 should have stunTrait
// So : class hero1 extends stunTrait(AHero)
// stunTrait.move() will be called after, so stunned will not be applied
// How make compostion without breaking inheritance ?


推荐答案

OP给出的设计决定针对的是移动已经从侧实施的行为。

The OP's given design decision targets the modification of the move behavior that already has been implemented from the class side.

因此 stun 行为不仅负责实现其 stun 特定的状态处理,还必须决定是否和/或如何更改移动行为的控制流程。

Thus a stun behavior is not only responsible for implementing its stun specific state handling, it also has to decide whether and/or how to change a move behavior's control flow.

为此依赖现有的实现,不仅 move ,还依赖于 setSpeed

For this it relies on existing implementations not only of move but also on setSpeed.

mixin的概念实际上不适合OP的方法,只是将其他行为混合到其他对象中。但是给定的特殊情况也必须处理 move 的命名冲突。这就是特征所针对的东西。

The concept of mixins really does not fit with the OP's approach for it just mixes additional behavior into other objects. But the given special case has to handle the naming conflict of move too. And that's something what traits are for.

如果在JavaScript中,曾经有一个真正支持的适用类型必须具备两种成分特性和对象组成,以及方法修改,可能的解决方案看起来可能类似于下一个提供的解决方案。

If, in JavaScript, there once was a real support for applicable types which have to be capable of both kinds of composition trait- and object-composition, as well as of method modification, a possible solution might look similar to the next provided one.

const withStunBehavior = Trait.create(function (use, applicator) {

  function moveInterceptor(proceedMove, interceptor, argsArray) {
  //console.log("withStunBehavior::moveInterceptor - this.isStunned() : ", this.isStunned());
    if (this.isStunned()) {

      this.setSpeed(0);
    }/* else {
      return proceedMove.call(this);
    }*/
    return proceedMove.call(this);
  }

  applicator(function (isStunnedValue) {
    isStunnedValue = !!isStunnedValue;
  //console.log("withStunBehavior::applicator - isStunnedValue : ", isStunnedValue);

    this.beStun = function beStun () {
      isStunnedValue = true;
    };
    this.unban = function unban () {
      isStunnedValue = false;
    };
    this.isStunned = function isStunned () {
      return isStunnedValue;
    };

  }).requires([

    "setSpeed",
    "move"

  ]).around(

    "move", moveInterceptor
  );
});


class AHero {
  constructor(stateValue) {
    var
      aHero = this;

    aHero.getSpeed = function getSpeed () {
      return stateValue.moveSpeed;
    };
    aHero.setSpeed = function setSpeed (speedValue) {
      return (stateValue.moveSpeed = speedValue);
    };

    // withStunBehavior.call(aHero);
  }
  move() {
    var
      speedValue = this.getSpeed();

    if (speedValue === 0) {
      console.log("Hero does not move at all. Its speed is " + speedValue + ".");
    } else {
      console.log("Hero moves with speed " + speedValue + ".");
    }
    return speedValue;
  }
}


class AHeroWithStunBehavior extends AHero {

  constructor(stateValue) {
    super(stateValue);

    withStunBehavior.call(this);
  }
}


var
  hero = new AHero({ x: 0, y: 0, moveSpeed: 200 });

console.log("\n");
console.log("hero.getSpeed() : ", hero.getSpeed());
console.log("hero.move() : ", hero.move());
console.log("\n");
console.log("hero.setSpeed(0) : ", hero.setSpeed(0));
console.log("hero.getSpeed() : ", hero.getSpeed());
console.log("hero.move() : ", hero.move());
console.log("\n");
console.log("hero.setSpeed(100) : ", hero.setSpeed(100));
console.log("hero.getSpeed() : ", hero.getSpeed());
console.log("hero.move() : ", hero.move());
console.log("\n");
console.log("hero.isStunned : ", hero.isStunned);
console.log("hero.beStun : ", hero.beStun);
console.log("hero.unban : ", hero.unban);

var
  stunningHero = new AHeroWithStunBehavior({ x: 40, y: 50, moveSpeed: 130 });

console.log("\n");
console.log("stunningHero.isStunned : ", stunningHero.isStunned);
console.log("stunningHero.beStun : ", stunningHero.beStun);
console.log("stunningHero.unban : ", stunningHero.unban);
console.log("\n");
console.log("stunningHero.getSpeed() : ", stunningHero.getSpeed());
console.log("stunningHero.move() : ", stunningHero.move());
console.log("\n");
console.log("stunningHero.setSpeed(0) : ", stunningHero.setSpeed(0));
console.log("stunningHero.getSpeed() : ", stunningHero.getSpeed());
console.log("stunningHero.move() : ", stunningHero.move());
console.log("\n");
console.log("stunningHero.setSpeed(90) : ", stunningHero.setSpeed(90));
console.log("stunningHero.getSpeed() : ", stunningHero.getSpeed());
console.log("stunningHero.move() : ", stunningHero.move());
console.log("\n");
console.log("stunningHero.beStun() : ", stunningHero.beStun());
console.log("stunningHero.move() : ", stunningHero.move());
console.log("\n");
console.log("stunningHero.setSpeed(160) : ", stunningHero.setSpeed(160));
console.log("stunningHero.getSpeed() : ", stunningHero.getSpeed());
console.log("stunningHero.move() : ", stunningHero.move());
console.log("\n");
console.log("stunningHero.unban() : ", stunningHero.unban());
console.log("stunningHero.move() : ", stunningHero.move());
console.log("\n");
console.log("stunningHero.setSpeed(160) : ", stunningHero.setSpeed(160));
console.log("stunningHero.getSpeed() : ", stunningHero.getSpeed());
console.log("stunningHero.move() : ", stunningHero.move());

.as-console-wrapper { max-height: 100%!important; top: 0; }

<script>(function(r){function g(a){var c="none",b;Y(a)&&(ta(a)?c=ua:(b=Z(a),t("^class\\s+"+a.name+"\\s+\\{").test(b)?c=va:t("\\([^)]*\\)\\s+=>\\s+\\(").test(b)?c=wa:z(a)&&(c=xa(a)?ya:za(a)||Aa(a)||Ba(a)?Ca:aa)));return c===aa}function C(a){return["^\\[object\\s+",a,"\\]$"].join("")}function v(a,c){var b=Da[c];return!!b&&0<=b.indexOf(a)}function M(a,c,b){return function(){var d=arguments;c.apply(b,d);return a.apply(b,d)}}function N(a,c,b){return function(){var d=arguments,e=a.apply(b,d);c.apply(b,d);return e}}function Ea(a,c,b,d){return function(){var e=arguments;c.call(b,e,d);return a.apply(b,e)}}function Fa(a,c,b,d){return function(){var e=arguments,f=a.apply(b,e);c.call(b,e,d);return f}}function Ga(a,c,b,d){return function(){var e=arguments,f=a.apply(b,e);c.call(b,f,e,d);return f}}function Ha(a,c,b,d){return function(){var e=arguments,f;try{f=a.apply(b,e)}catch(l){c.call(b,l,e,d)}return f}}function Ia(a,c,b,d){return function(){var e=arguments,f,g;try{f=a.apply(b,e)}catch(m){g=m}c.call(b,g||f,e,d);return f}}function Ja(a,c,b,d){return function(){return c.call(b,a,c,arguments,d)}}function Ka(a,c){return function(){var b=this[a];g(b)||(b=u);this[a]=M(b,c,this)}}function La(a,c){return function(){var b=this[a];g(b)||(b=u);this[a]=N(b,c,this)}}function Ma(a,c){return function(b){var d=this[a];g(d)||(d=u);this[a]=Ea(d,c,this,b)}}function Na(a,c){return function(b){var d=this[a];g(d)||(d=u);this[a]=Fa(d,c,this,b)}}function Oa(a,c){return function(b){var d=this[a];g(d)||(d=u);this[a]=Ga(d,c,this,b)}}function Pa(a,c){return function(b){var d=this[a];g(d)||(d=u);this[a]=Ha(d,c,this,b)}}function Qa(a,c){return function(b){var d=this[a];g(d)||(d=u);this[a]=Ia(d,c,this,b)}}function Ra(a,c){return function(b){var d=this[a];g(d)||(d=u);this[a]=Ja(d,c,this,b)}}function ba(a,c,b){a.useTraits.rules.push(new A({type:"without",traitList:c,methodNameList:b}))}function ca(a,c,b,d){a.useTraits.rules.push(new A({type:"as",trait:c,methodName:b,methodAlias:d}))}function da(a){return ea(p(a)).reduce(function(a,b){q(b)&&a.push(F(b));return a},[])}function fa(){var a,c,b,d,e;if(O(this))if(d=this.valueOf(),e=d.parentLink,w(e))if(b=e.getSetup(),a=b.chainData,c=a.recentCalleeName,v(c,"without"))if(c=da(arguments),1<=c.length)a.recentCalleeName="without",ba(b,d.traitList,c);else throw new h("Not even a single <String> type was passed to 'without' as to be excluded method name.");else{a=["\u2026 invalid chaining of '",c,"().without()'"].join("");if("applyBehavior"==c)throw new n([a," in case of excluding one or more certain behaviors."].join(""));throw new n(a);}else throw new k("Please do not spoof the context of 'use'.");else throw new k("Please do not spoof the context of 'apply'.");return e}function P(a,c){var b=a.getSetup();if(Sa(c,a.valueOf().traitList))b.chainData.recentCalleeName="applyTraits",b=new Q({traitList:c,parentLink:a}),a.putChild(b);else throw new h("Any trait that got passed to 'apply' needs to be registered before via 'use'.");return b}function Sa(a,c){return a.every(function(a){return 0<=c.indexOf(a)})}function Ta(){var a;a=this.getSetup();var c=this.valueOf().traitList;I(this,a,a.chainData.recentCalleeName);a=P(this,c);return fa.apply(a,arguments)}function Ua(){var a=this.getSetup(),c=this.valueOf().traitList;I(this,a,a.chainData.recentCalleeName);return P(this,c)}function ga(){var a,c,b;b=p(arguments);if(w(this))if(a=this.getSetup(),c=a.chainData,c=c.recentCalleeName,I(this,a,c),a=["\u2026 invalid chaining of '",c,"().apply()'"].join(""),v(c,"apply"))if(x(b[0]))if(q(b[1]))if(v(c,"applyBehavior")){c=b[0];b=F(b[1]);a=this.getSetup();var d;if(0<=this.valueOf().traitList.indexOf(c))if(d={},c.call(d),g(d[b]))a.chainData.recentCalleeName="applyBehavior",b=new R({trait:c,methodName:b,parentLink:this}),this.putChild(b);else throw new k(["The requested '",b,"' method has not been implemented by the trait that got passed to 'apply'."].join(""));else throw new h("Any trait that got passed to 'apply' needs to be registered before via 'use'.");}else throw new n([a," in case of applying just a certain behavior."].join(""));else if(p(b).every(x))if(v(c,"applyTraits"))b=P(this,b);else throw new n([a," in case of applying from one or more traits."].join(""));else throw new h("'apply(\u2026)' excepts either, as its 2nd delimiting argument, just a 'String' type or exclusively one or more 'Trait' and 'Function' types.");else throw new h("'apply(<Trait|Function>, \u2026)' excepts as its 1st argument explicitly either a 'Trait' or a 'Function' type.");else throw new n(a);else throw new k("'use(\u2026).apply(\u2026)' only works within a validly chained context, please do not try spoofing the latter.");return b}function ha(){var a;a=this;if(O(a)||G(a))a=a.valueOf(),a=a.parentLink,a=ga.apply(a,arguments);else throw new k("Please do not spoof the context of 'apply'.");return a}function I(a,c,b){var d,e;a&&!c.chainData.isTerminated&&(d=a.getChild())&&(e=d.valueOf())&&("applyTraits"==b&&O(d)?ba(c,e.traitList,[]):"applyBehavior"==b&&G(d)&&(a=e.methodName,ca(c,e.trait,a,a)));c.chainData.recentCalleeName="apply"}function R(a){this.valueOf=function(){return{trait:a.trait,methodName:a.methodName,parentLink:a.parentLink}};this.toString=function(){return["ApplyLink::singleBehavior :: ",S.stringify(a)].join("")};return this}function G(a){var c;return null!=a&&(a instanceof R||g(a.as)&&g(a.after)&&g(a.before)&&g(a.valueOf)&&(c=a.valueOf())&&x(c.trait)&&q(c.methodName)&&w(c.parentLink))}function Q(a){this.valueOf=function(){return{traitList:a.traitList,parentLink:a.parentLink}};this.toString=function(){return["ApplyLink::fromTraits :: ",S.stringify(a)].join("")};return this}function O(a){var c;return null!=a&&(a instanceof Q||g(a.without)&&g(a.valueOf)&&(c=a.valueOf())&&T(c.traitList)&&w(c.parentLink))}function U(a,c){var b=null;this.getSetup=function(){return c};this.deleteChild=function(){b=null};this.putChild=function(a){b=a};this.getChild=function(){return b};this.valueOf=function(){return{traitList:p(a.traitList)}};this.toString=function(){return["UseRoot :: ",S.stringify(a)].join("")};this.apply=ga.bind(this);this.apply.all=Ua.bind(this);this.apply.all.without=Ta.bind(this);return this}function w(a){var c;return null!=a&&(a instanceof U||g(a.apply)&&g(a.valueOf)&&g(a.getSetup)&&(c=a.valueOf())&&T(c.traitList)&&(c=a.getSetup())&&ia(c))}function Va(a,c){var b=this.applicator,d=b.root,e=b.modifiers;b.canRequire=!1;if(q(a))if(g(c))e.push(Ka(a,c));else throw new h("'before(\u2026, <Function>)' excepts as its 2nd argument just a 'Function' type.");else throw new h("'before(<String>, \u2026)' excepts as its 1st argument just a 'String' type.");return d}function Wa(a,c){var b=this.applicator,d=b.root,e=b.modifiers;b.canRequire=!1;if(q(a))if(g(c))e.push(Ma(a,c));else throw new h("'before.stateful(\u2026, <Function>)' excepts as its 2nd argument just a 'Function' type.");else throw new h("'before.stateful(<String>, \u2026)' excepts as its 1st argument just a 'String' type.");return d}function Xa(a,c){var b=this.applicator,d=b.root,e=b.modifiers;b.canRequire=!1;if(q(a))if(g(c))e.push(La(a,c));else throw new h("'after(\u2026, <Function>)' excepts as its 2nd argument just a 'Function' type.");else throw new h("'after(<String>, \u2026)' excepts as its 1st argument just a 'String' type.");return d}function Ya(a,c){var b=this.applicator,d=b.root,e=b.modifiers;b.canRequire=!1;if(q(a))if(g(c))e.push(Na(a,c));else throw new h("'after.stateful(\u2026, <Function>)' excepts as its 2nd argument just a 'Function' type.");else throw new h("'after.stateful(<String>, \u2026)' excepts as its 1st argument just a 'String' type.");return d}function Za(a,c){var b=this.applicator,d=b.root,e=b.modifiers;b.canRequire=!1;if(q(a))if(g(c))e.push(Oa(a,c));else throw new h("'afterReturning(\u2026, <Function>)' excepts as its 2nd argument just a 'Function' type.");else throw new h("'afterReturning(<String>, \u2026)' excepts as its 1st argument just a 'String' type.");return d}function $a(a,c){var b=this.applicator,d=b.root,e=b.modifiers;b.canRequire=!1;if(q(a))if(g(c))e.push(Pa(a,c));else throw new h("'afterThrowing(\u2026, <Function>)' excepts as its 2nd argument just a 'Function' type.");else throw new h("'afterThrowing(<String>, \u2026)' excepts as its 1st argument just a 'String' type.");return d}function ab(a,c){var b=this.applicator,d=b.root,e=b.modifiers;b.canRequire=!1;if(q(a))if(g(c))e.push(Qa(a,c));else throw new h("'afterFinally(\u2026, <Function>)' excepts as its 2nd argument just a 'Function' type.");else throw new h("'afterFinally(<String>, \u2026)' excepts as its 1st argument just a 'String' type.");return d}function bb(a,c){var b=this.applicator,d=b.root,e=b.modifiers;b.canRequire=!1;if(q(a))if(g(c))e.push(Ra(a,c));else throw new h("'around(\u2026, <Function>)' excepts as its 2nd argument just a 'Function' type.");else throw new h("'around(<String>, \u2026)' excepts as its 1st argument just a 'String' type.");return d}function cb(){var a=this.applicator,c=a.root,b=a.didRequire;if(a.canRequire)if(a.canRequire=!1,a.didRequire=!0,b=da(arguments),1<=b.length)a.requires=b;else throw new h("Not even a single <String> type was passed to 'requires' as method name that a trait, at its apply time, expects to be present at least.");else{if(b)throw new n("'requires' can be invoked exactly once, right after having executed a trait's 'applicator' method.");throw new n("'requires' can not bee invoked after a modifier method, but has to be the direct follower of a trait's 'applicator' method.");}return c}function db(a){I(this.useTraits.root,this,this.chainData.recentCalleeName);this.chainData.isTerminated=!0;var c=this.applicator,b=this.useTraits.rules,d=0>=b.length;if(!d&&!ja(b))throw new k("The trait composition language's rule set does not result in applicable behavior. This happens e.g. if all behavior has been deleted via 'without'.");if(null!=a)if(g(a=F(a)))c.body=a,a.call(c.proxy);else throw new h("The applicator should either stay empty or receive a sole applicable type like a 'Trait' or a 'Function' type.");else d&&0>=c.modifiers.length&&D.warn("The trait descriptor till now did neither receive an applicable function via the 'applicator' method nor any composition rule via 'use(\u2026).apply(\u2026)' nor any method modifier.");return c.root}function eb(){var a;a=ea(p(arguments)).filter(function(a){return x(a)});if(1<=a.length)a=new U({traitList:a},this);else throw new h("Not even a single valid 'Trait' or 'Function' type has been provided to 'use(<Trait|Function>[, \u2026])'.");return this.useTraits.root=a}function y(a,c){return a.findIndex(function(a){return a.trait===c})}function ka(a){return{type:a.type,trait:a.trait,methodName:a.methodName}}function la(a){return{type:a.type,trait:a.trait,fromTrait:a.fromTrait,methodName:a.methodName}}function A(a){this.valueOf=function(){return fb[a.type](a)}}function ja(a){var c=!0;if(1<=a.length){var b={},c=ma(a),d=na(c);d.forEach(function(a){a.trait.call(a.proxy)});a.forEach(function(a){a.execute(b,d)});c=1<=J(b).length}return c}function gb(a,c,b){var d;if(b[0]!==oa&&(d=c.reduce(function(b,c){g(a[c])||b.push(c);return b},[]),1<=d.length))throw new h("The type misses following required method(s) \u2026 '"+d.join("', '")+"'.");return d}function hb(a,c,b){a.forEach(function(a){a.call(c,b)})}function ib(a){this.call=function(){var c=p(arguments),b;b=c.shift();b=null!=b&&b||null;a.apply(b,c);return b};this.apply=function(c,b){null==b&&(b=[]);c=null!=c&&c||null;a.apply(c,b);return c};return this}function jb(a){this.requires=function(){return p(a)};return this}function kb(a){var c=[],b={};a.call(b,oa);c=J(b).sort(function(a,b){return a<b&&-1||a>b&&1||0});b=null;this.keys=function(){return p(c)};return this}function pa(a,c){this.toString=function(){return"[object Trait]"};this.valueOf=function(){return a};ib.call(this,a);jb.call(this,c);kb.call(this,a);return this}function qa(a){var c;if(c=!!a)(c=a instanceof pa)||(c="object"==typeof a&&g(a.call)&&g(a.apply)&&g(a.valueOf)&&g(a.valueOf()));return c}function x(a){return qa(a)||g(a)}function ma(a){return a.reduce(function(a,b){var c=b.valueOf(),e=c.trait,f=c.fromTrait;e&&0>a.indexOf(e)&&a.push(e);f&&0>a.indexOf(f)&&a.push(f);(c.traitList||[]).forEach(function(b){0>a.indexOf(b)&&a.push(b)});return a},[])}function na(a){return a.map(function(a){return{trait:a,proxy:{}}})}function lb(a,c,b,d){var e=[],f={};if(!(0>=c.length||ja(c)))throw new k("The trait composition language's rule set does not result in applicable behavior. This happens e.g. if all behavior has been deleted via 'without'.");g(b)&&(b.call(f),e=J(f));return[a,c,e,d].some(function(a){return 1<=a.length})}function mb(a){var c,b=a.useTraits.rules,d=a.applicator;a=d.body;var e=d.requires,d=d.modifiers,f=ma(b);lb(f,b,a,d)&&(d=function(a,b,c,d,e){return function(){var f=this,h=p(arguments),l=na(a);l.forEach(function(a){a.trait.apply(a.proxy,h)});b.forEach(function(a){a.execute(f,l)});gb(f,c,h);g(d)&&d.apply(f,h);hb(e,f,h);return f}}(f,b,e,a,d),c=new pa(d,e));return c}var V=r.Function,H=r.Object,B=r.Array,t=r.RegExp,S=r.JSON,h=r.TypeError,k=r.ReferenceError,n=r.SyntaxError,nb=V.prototype,K=H.prototype,ra=U.prototype,sa=Q.prototype,L=R.prototype,oa={},aa="applicable-function",ya="buildin-constructor",va="class-constructor",wa="arrow-function",ua="generator-function",Ca="interface-type",Da={without:["apply","applyTraits"],as:["apply","applyBehavior"],after:["apply","applyBehavior","after","before"],before:["apply","applyBehavior","after","before"],apply:"apply applyBehavior applyTraits without as after before use".split(" "),applyTraits:"apply applyBehavior applyTraits without as after before use".split(" "),applyBehavior:"apply applyBehavior applyTraits without as after before use".split(" ")},fb={beforeWrap:ka,afterWrap:ka,beforeApply:la,afterApply:la,without:function(a){return{type:a.type,traitList:p(a.traitList),methodNameList:p(a.methodNameList)}},as:function(a){return{type:a.type,trait:a.trait,methodName:a.methodName,methodAlias:a.methodAlias}}},ob={beforeWrap:function(a,c,b){var d=y(b,a.trait);b=b[d];a=a.methodName;c[a]=M((b&&b.proxy||{})[a],c[a],c)},afterWrap:function(a,c,b){var d=y(b,a.trait);b=b[d];a=a.methodName;c[a]=N((b&&b.proxy||{})[a],c[a],c)},beforeApply:function(a,c,b){var d=y(b,a.trait),e=y(b,a.fromTrait),d=b[d],e=b[e];b=d&&d.proxy||{};e=e&&e.proxy||{};a=a.methodName;a in c&&delete c.methodName;c[a]=M(b[a],e[a],c)},afterApply:function(a,c,b){var d=y(b,a.trait),e=y(b,a.fromTrait),d=b[d],e=b[e];b=d&&d.proxy||{};e=e&&e.proxy||{};a=a.methodName;a in c&&delete c.methodName;c[a]=N(b[a],e[a],c)},without:function(a,c,b){var d=a.traitList,e=a.methodNameList.reduce(function(a,b){a[b]=null;return a},{});d.forEach(function(a){a=y(b,a);var d=(a=b[a])&&a.proxy||{};J(d).forEach(function(a){a in e||(a in c&&delete c.methodName,c[a]=function(a,b){return function(){return a.apply(b,arguments)}}(d[a],c))})});a=b=d=e=null},as:function(a,c,b){var d=y(b,a.trait);b=(b=b[d])&&b.proxy||{};d=a.methodAlias;a=a.methodName;d in c&&delete c.methodAlias;c[d]=function(a,b){return function(){return a.apply(b,arguments)}}(b[a],c);a=b=d=b=b=d=a=null}},F=function(a,c){return function(b){return b==c?b:a.call(b).valueOf()}}(K.valueOf,null),E=function(a){return function(c){return a.call(c)}}(K.toString),Z=function(a){return function(c){return a.call(c)}}(nb.toString),pb=function(a){try{a.call(null,"length"),a=function(a,b){return function(c,e){return c!=b&&a.call(c,e)}}(a,null)}catch(c){a=function(a,c){return function(b,d){var e=b!=c;if(e)try{e=a.call(b,d)}catch(m){e=!0}return e}}(a,null)}return a}(K.propertyIsEnumerable),Y=function(a){return function(c){return typeof c==a}}(typeof V),z=function(a){return function(c){return Y(c)&&typeof c.call==a&&typeof c.apply==a}}(typeof V),qb=function(a){return function(c){return t(a).test(E(c))}}(C("Function")),ia=function(a){return function(c){return t(a).test(E(c))}}(C("Object")),rb=z(H.getPrototypeOf)&&H.getPrototypeOf||function(a){var c=a&&a.__proto__;return c||null===c?c:qb(a.constructor)?a.constructor.prototype:a instanceof H?K:null},W=function(a){return function(c){return(c=t(a).exec(Z(c)))&&c[1]}}("^function\\s+([^(]+)\\("),xa=function(a){return function(c){return t(a).test(W(c))}}("^(?:Array|ArrayBuffer|AsyncFunction|Atomics|Boolean|DataView|Date|Error|EvalError|Float32Array|Float64Array|Function|Generator|GeneratorFunction|Int16Array|Int32Array|Int8Array|InternalError|Collator|DateTimeFormat|NumberFormat|Iterator|Map|Number|Object|Promise|Proxy|RangeError|ReferenceError|RegExp|Bool16x8|Bool32x4|Bool64x2|Bool8x16|Float32x4|Float64x2|Int16x8|Int32x4|Int8x16|Uint16x8|Uint32x4|Uint8x16|Set|SharedArrayBuffer|StopIteration|String|Symbol|SyntaxError|TypeError|TypedArray|URIError|Uint16Array|Uint32Array|Uint8Array|Uint8ClampedArray|WeakMap|WeakSet)$"),X=function(a,c){var b=t(c);return b.test(W(a))||b.test(W(rb(a)))},za=function(a){return function(c){return X(c,a)}}("^(?:Node|CharacterData|Event|DOMError|DOMException|DOMImplementation|DOMStringList|DOMTokenList|EventTarget|HTMLCollection|MutationObserver|MutationRecord|NodeFilter|NodeIterator|NodeList|Range|TreeWalker|URL|Document)$"),Aa=function(a){return function(c){return X(c,a)}}("^(?:HTMLElement|HTMLMediaElement|Element)$"),Ba=function(a){return function(c){return X(c,a)}}("^(?:CanvasRenderingContext2D|CanvasGradient|CanvasPattern|TextMetrics|ImageData|DOMStringMap|MediaError|HTMLCollection|NodeList)$"),ta=function(a){return function(c){return t(a).test(E(c))}}(C("GeneratorFunction")),q=function(a){return function(c){return t(a).test(E(c))}}(C("String")),T=z(B.isArray)&&B.isArray||function(a){return function(c){return t(a).test(E(c))}}(C("Array")),sb=z(B.isArguments)&&B.isArguments||function(a,c){var b=function(b){return t(a).test(E(b))};b(arguments)||(b=function(a){return ia(a)&&"number"==typeof a.length&&c(a.length)&&!pb(a,"length")});return b}(C("Arguments"),r.Number.isFinite),p=z(B.from)&&B.from||function(a){return function(c){return a.call(c)}}(B.prototype.slice),ea=function c(b){b=sb(b)&&p(b)||b;T(b)&&(b=b.reduce(function(b,e){return b.concat(c(e))},[]));return b},J=H.keys,u=function(){},D;D=(D=r.console)&&z(D.warn)&&z(D.log)&&D||{warn:u,log:u};L.as=function(c){var b,d,e,f,g;if(G(this))if(f=this.valueOf(),g=f.parentLink,w(g))if(e=g.getSetup(),d=e.chainData,b=d.recentCalleeName,v(b,"as"))if(q(c=F(c)))if(b=f.trait,f=f.methodName,f!==c)d.recentCalleeName="as",ca(e,b,f,c);else throw new h("Using identical method names in case of aliasing is considered to be a rule violating contradiction.");else throw new h("'as(<String>)' excepts as its sole argument just a 'String' type.");else{c=["\u2026 invalid chaining of '",b,"().as()'"].join("");if("applyTraits"==b)throw new n([c," in case of aliasing just a certain behavior."].join(""));throw new n(c);}else throw new k("Please do not spoof the context of 'use'.");else throw new k("Please do not spoof the context of 'apply'.");return g};L.after=function(c){var b,d,e,f,l,m;if(G(this))if(f=this.valueOf(),m=f.parentLink,w(m))if(e=m.getSetup(),d=e.chainData,b=d.recentCalleeName,v(b,"after"))if(x(c))if(b=m.valueOf(),b=b.traitList,0<=b.indexOf(c))if(b=f.trait,b!==c)if(l=f.methodName,f={},c.call(f),g(f[l]))d.recentCalleeName="after",e.useTraits.rules.push(new A({type:"afterApply",trait:c,fromTrait:b,methodName:l}));else throw new k(["Please consider applying '",l,"' directly. This expected behavior has not been implemented by the trait that got passed to 'after'."].join(""));else throw new k("Passing identical trait references to both 'apply' and 'after' is a contradiction that violates the composition rules.");else throw new h("Any trait passed to 'after' has to be registered before via 'use'.");else throw new h("'after(<Trait|Function>)' excepts as its sole argument explicitly either a 'Trait' or a 'Function' type.");else throw new n(["\u2026 invalid chaining of '",b,"().after()'"].join(""));else throw new k("Please do not spoof the context of 'use'.");else throw new k("Please do not spoof the context of 'apply'.");return m};L.before=function(c){var b,d,e,f,l,m;if(G(this))if(f=this.valueOf(),m=f.parentLink,w(m))if(e=m.getSetup(),d=e.chainData,b=d.recentCalleeName,v(b,"before"))if(x(c))if(b=m.valueOf(),b=b.traitList,0<=b.indexOf(c))if(b=f.trait,b!==c)if(l=f.methodName,f={},c.call(f),g(f[l]))d.recentCalleeName="before",e.useTraits.rules.push(new A({type:"beforeApply",trait:c,fromTrait:b,methodName:l}));else throw new k(["Please consider applying '",l,"' directly. This expected behavior has not been implemented by the trait that got passed to 'before'."].join(""));else throw new k("Passing identical trait references to both 'apply' and 'before' is a contradiction that violates the composition rules.");else throw new h("Any trait passed to 'before' has to be registered before via 'use'.");else throw new h("'before(<Trait|Function>)' excepts as its sole argument explicitly either a 'Trait' or a 'Function' type.");else throw new n(["\u2026 invalid chaining of '",b,"().before()'"].join(""));else throw new k("Please do not spoof the context of 'use'.");else throw new k("Please do not spoof the context of 'apply'.");return m};L.apply=ha;sa.without=fa;sa.apply=ha;ra.after=function(c){var b,d,e,f;if(w(this))if(e=this.getSetup(),d=e.chainData,b=d.recentCalleeName,v(b,"after"))if(x(c))if(b=this.valueOf(),b=b.traitList,0<=b.indexOf(c))if(b=this.getChild(),f=b.valueOf(),b=f.trait,b!==c)if(f=f.methodName,b={},c.call(b),g(b[f]))d.recentCalleeName="after",e.useTraits.rules.push(new A({type:"afterWrap",trait:c,methodName:f}));else throw new k(["Please consider applying '",f,"' directly. This expected behavior has not been implemented by the trait that got passed to 'after'."].join(""));else throw new k("Passing identical trait references to both 'apply' and 'after' is a contradiction that violates the composition rules.");else throw new h("Any trait passed to 'after' has to be registered before via 'use'.");else throw new h("'after(<Trait|Function>)' excepts as its sole argument explicitly either a 'Trait' or a 'Function' type.");else throw new n(["\u2026 invalid chaining of '",b,"().after()'"].join(""));else throw new k("Please do not spoof the context of 'use'.");return this};ra.before=function(c){var b,d,e,f;if(w(this))if(e=this.getSetup(),d=e.chainData,b=d.recentCalleeName,v(b,"before"))if(x(c))if(b=this.valueOf(),b=b.traitList,0<=b.indexOf(c))if(b=this.getChild(),f=b.valueOf(),b=f.trait,b!==c)if(f=f.methodName,b={},c.call(b),g(b[f]))d.recentCalleeName="before",e.useTraits.rules.push(new A({type:"beforeWrap",trait:c,methodName:f}));else throw new k(["Please consider applying '",f,"' directly. This expected behavior has not been implemented by the trait that got passed to 'before'."].join(""));else throw new k("Passing identical trait references to both 'apply' and 'before' is a contradiction that violates the composition rules.");else throw new h("Any trait passed to 'before' has to be registered before via 'use'.");else throw new h("'before(<Trait|Function>)' excepts as its sole argument explicitly either a 'Trait' or a 'Function' type.");else throw new n(["\u2026 invalid chaining of '",b,"().before()'"].join(""));else throw new k("Please do not spoof the context of 'use'.");return this};A.prototype.execute=function(c,b){var d=this.valueOf();ob[d.type](d,c,b)};return r.Trait={create:function(c){var b,d,e;g(c=F(c))&&(e={chainData:{isTerminated:!1,recentCalleeName:"use"},useTraits:{root:null,rules:[]},applicator:{body:null,proxy:{},root:{},modifiers:[],requires:[],canRequire:!0,didRequire:!1}},b=e.applicator.root,b.requires=cb.bind(e),b.before=Va.bind(e),b.after=Xa.bind(e),b.before.stateful=Wa.bind(e),b.after.stateful=Ya.bind(e),b.afterReturning=Za.bind(e),b.afterThrowing=$a.bind(e),b.afterFinally=ab.bind(e),b.around=bb.bind(e),b=eb.bind(e),d=db.bind(e),c(b,d),e=mb(e));return e},isTrait:qa,isApplicable:x}})(Function("return this")());</script>

这篇关于JS中的组合和混合的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆