Comment détecter la fin d’une chaîne de méthodes en JavaScript?

Premièrement et surtout, j’essaie de détecter l’appel final d’une chaîne de méthodes. J’aimerais également trouver un moyen de détecter le nombre de méthodes “dans” ou “vers le bas” d’une chaîne d’objects dans les appels de méthodes d’une chaîne.

Par exemple, dans le plugin, j’écris:

var result = $("#someDiv").myPlugin.foo().bar()._foo()._bar(); 

Supposons que la méthode est en cours d’exécution dans .bar (). J’aimerais savoir que je suis 2 méthodes dans la chaîne.

La raison pour laquelle j’ai besoin d’extraire ces informations d’une manière ou d’une autre est que lorsque j’atteins la dernière méthode de la chaîne, je peux renvoyer un résultat au lieu de l’object plugin, rompant ainsi la chaîne à ce moment-là afin d’accéder à nos données dans le répertoire. “résultat” variable.

Voici un exemple tiré de votre projet :

 var strLenA = parseInt( P.strlen('some ssortingng').data ); var strLenB = parseInt( P.strlen('another ssortingng').data ); var totalStrLen = strLenA + strLenB; console.log(strLenA, strLenB, totalStrLen); 

Je peux donc comprendre pourquoi nos réponses ne sont pas vraiment adéquates – et pourquoi vous voulez vous débarrasser des .data . Heureusement, votre .data retourne toujours une chaîne, de toute façon. Vous pouvez donc utiliser le remplacement mystique .toSsortingng pour que vos méthodes renvoient toujours une copie de la méthode parente, mais également pour leur permettre d’être traitées comme des chaînes.

Voici un exemple: [avec un violon ]

 var ssortingngMagic = function() { var chain = "", self = this; self.toSsortingng = function () { return chain; }; // Where the real magic happens. self.add = function(str) { chain += str + " "; return self; }; }; var magi = new ssortingngMagic(); alert(magi.add("hello").add("world")); // Alerts, "hello world" magi.add("and").add("thanks").add("for").add("all").add("the").add("fish"); alert(magi); // Alerts, "hello world and thanks for all the fish" 

Dans votre cas, probablement tout ce que vous auriez à faire est de changer .data en P à .toSsortingng et l’ envelopper dans une fonction.

Dans l’avenir , lorsque vous ajoutez le support pour d’ autres types de données comme les numéros et les booléens, vous pouvez utiliser valueOf de la même manière que vous utilisez toSsortingng . En fait, vous devriez également continuer à inclure toSsortingng lorsque la valeur de retour n’est pas une chaîne, mais qu’ils traitent ce nombre comme une chaîne, comme dans console.log ou $.fn.text . Voici l’exemple ci-dessus, mais avec des chiffres: http://jsfiddle.net/emqVe/1/

Par souci d’exhaustivité. Une autre alternative consiste à transmettre un object qui sera mis à jour au fur et à mesure que la chaîne avance. Cela vous permettrait d’accéder à la valeur du résultat quand bon vous semble (au lieu d’avoir à l’append à la fin de la chaîne).

Au lieu d’une syntaxe comme celle-ci:

 var result = chainableFunction.doThis().doThat().result; 

Vous auriez alors:

 chainableFunction.update(variableToUpdate).doThis().doThat(); var result = variableToUpdate.result; 

La logique est très semblable à la solution proposée par d’autres. Lequel utiliser dépend probablement de vos cas d’utilisation. Un problème possible de devoir terminer la chaîne avec .result est que rien ne vous empêche de l’utiliser de cette façon:

 var chainedUp = chainableFunction.doThis().doThat(); doSomething(chainedUp.result); ... chainedUp.doOneMoreThing() ... doSomething(chainedUp.result); // oups, .result changed! 

Avec l’option variableToUpdate, la valeur du résultat n’est pas affectée par les futurs appels de fonction. Encore une fois, cela pourrait être souhaitable dans certains contextes, pas dans d’autres.

Exemple complet ci-dessous

 #!/usr/bin/env node var ChainUp = {}; (function(Class) { // Pure functions have no access to state and no side effects var Pure = {}; Pure.isFunction = function(fn) { return fn && {}.toSsortingng.call(fn) === '[object Function]'; }; Class.instance = function() { var instance = {}; var result; var updateRef; function callBack(fn) { // returning a clone, not a reference. if(updateRef) { updateRef.r = (result || []).slice(0); } if(Pure.isFunction(fn)) { fn(result); } } instance.update = function(obj) { updateRef = obj; return instance; }; instance.one = function(cb) { result = (result || []); result.push("one"); callBack(cb); return instance; }; instance.two = function(cb) { result = (result || []); result.push("two"); callBack(cb); return instance; }; instance.three = function(cb) { result = (result || []); result.push("three"); callBack(cb); return instance; }; instance.result = function() { return result; }; return instance; }; }(ChainUp)); var result1 = {}; var chain = ChainUp.instance().update(result1); var one = chain.one(console.log); // [ 'one' ] console.log(one.result()); // [ 'one' ] console.log(result1.r); // [ 'one' ] var oneTwo = chain.two(); console.log(oneTwo.result()); // [ 'one', 'two' ] console.log(result1.r); // [ 'one', 'two' ] var result2 = {}; var oneTwoThree = chain.update(result2).three(); console.log(oneTwoThree.result()); // [ 'one', 'two', 'three' ] console.log(result2.r); // [ 'one', 'two', 'three' ] console.log(result1.r); // [ 'one', 'two' ] 

Remarque. Les mots-clés de classe et d’instance sont probablement inconnus. C’est une convention que j’utilise lors de l’utilisation des fermetures au lieu d’inheritance prototypique pour construire des instances d’un prototype. Vous pouvez remplacer instance par self (et self = this au lieu de instance = {}) ..

Il n’est pas possible de déterminer si un appel est la dernière instance d’une chaîne lors de la détermination de la valeur de retour , et voici pourquoi:

 var result = $("#someDiv").myPlugin.foo().bar()._foo()._bar(); 

foo renvoie myPlugin sur la bar appelée, laquelle renvoie myPlugin sur laquelle _foo est appelée, laquelle renvoie myPlugin sur laquelle _bar est appelé.

Donc, effectivement, lorsque _foo renvoie sa valeur ( myPlugin ), c’est avant que cette valeur ne soit utilisée. À moins que _foo soit psychique, il ne peut pas savoir ce qui se passera ensuite.

Comme vous l’avez souligné dans vos commentaires, votre meilleur choix est d’avoir une méthode “fin”, comme pour les results() .

Une autre suggestion serait de passer un gestionnaire pour myPlugin qui est appelé à définir la valeur à l’ aide setTimeout(..., 0) . Ayez une valeur dans myPlugin que foo, bar, _foo et _bar soient tous définis. Appelons-le returnValue . Modifiez myPlugin pour accepter une méthode en tant que paramètre unique. Appelons ce handler . Le premier argument de cette méthode contiendra la valeur. Dans myPlugin, avant votre return , faites:

 window.setTimeout(function () { handler(returnValue); }, 0); 

Etant donné que le paramètre de fonction de setTimeout ne sera pas appelé jusqu’à la fin de l’exécution, il contiendra la dernière valeur définie pour returnValue à- returnValue la valeur définie par le dernier appel de la chaîne. Je considérerais cela le plus proche option de ce que vous essayez d’atteindre, étant donné que le développeur n’a pas à vous soucier de ses méthodes sont appelées dernière.

Il n’y a aucun moyen de savoir à l’ intérieur d’ une méthode (juridique ou facile ou agréable) ce qui se passe avec le résultat à l’ extérieur, après elle retourne avec elle. Vous devriez utiliser une méthode de “chaîne de fin”.

Repensez-vous, cherchez-vous la dernière méthode appliquée à un object ou souhaitez-vous détecter quelque chose de plus explicite? Peut-être perdez-vous la possibilité d’appliquer des méthodes à une décision (avec de faux noms de méthodes stupides):

 obj.turnLeft().pushUp().makeBig().makeSilent; if (colorSupport) { obj.paintRed(); } else { obj.paintSsortingpes(); } obj.makeShine().lastMethodCallSoObjectIsNowInFinalState(); 

Il n’y a pas de méthode native, cependant, vous pouvez append un paramètre à la méthode destinée à être chaînée à votre guise. Et déterminez si l’appel en cours est le dernier en le définissant sur true , comme dans:

 var AlertText = { text: "", chainEntry: function(textToAdd, isTheLastOne) { this.text += textToAdd; // Perform only if this is told to be the last call in the chain: if (isTheLastOne) { alert(this.text); this.text = ""; } // return this; } }; AlertText .chainEntry("Hi, ") .chainEntry("how ") .chainEntry("are ") .chainEntry("you?", true); // alert("Hi, how are you?");