J'ai certaines fonctions qui reçoivent (parfois pas toujours) un rappel et l'exécutent. Est-ce que vérifier si le rappel est défini/fonctionner est un bon style ou existe-t-il une meilleure façon?
Exemple:
function save (callback){
.....do stuff......
if(typeof callback !== 'undefined'){
callback();
};
};
Je préfère personnellement
typeof callback === 'function' && callback();
La commande typeof
est cependant douteuse et ne doit être utilisée que pour "undefined"
et "function"
Les problèmes avec le typeof !== undefined
est que l'utilisateur peut passer une valeur définie et pas une fonction
Vous pouvez également faire:
var noop = function(){}; // do nothing.
function save (callback){
callback = callback || noop;
.....do stuff......
};
C'est particulièrement utile si vous utilisez le callback
à quelques endroits.
De plus, si vous utilisez jQuery
, vous avez déjà une fonction comme ça, elle s'appelle $. Noop
Faites simplement
if (callback) callback();
Je préfère appeler le rappel s'il est fourni, quel que soit le type. Ne le laissez pas échouer en silence, afin que l'implémenteur sache qu'il a transmis un argument incorrect et peut le corriger.
// @param callback Default value is a noop fn.
function save(callback = ()=>{}) {
// do stuff...
callback();
}
Plutôt que de rendre le rappel facultatif, attribuez simplement une valeur par défaut et appelez-la
const identity = x =>
x
const save (..., callback = identity) {
// ...
return callback (...)
}
Lorsqu'elle est utilisée
save (...) // callback has no effect
save (..., console.log) // console.log is used as callback
Un tel style est appelé style passant-continuation . Voici un exemple réel, combinations
, qui génère toutes les combinaisons possibles d'une entrée de tableau
const identity = x =>
x
const None =
Symbol ()
const combinations = ([ x = None, ...rest ], callback = identity) =>
x === None
? callback ([[]])
: combinations
( rest
, combs =>
callback (combs .concat (combs .map (c => [ x, ...c ])))
)
console.log (combinations (['A', 'B', 'C']))
// [ []
// , [ 'C' ]
// , [ 'B' ]
// , [ 'B', 'C' ]
// , [ 'A' ]
// , [ 'A', 'C' ]
// , [ 'A', 'B' ]
// , [ 'A', 'B', 'C' ]
// ]
Étant donné que combinations
est défini dans le style de passage de continuation, l'appel ci-dessus est en fait le même
combinations (['A', 'B', 'C'], console.log)
// [ []
// , [ 'C' ]
// , [ 'B' ]
// , [ 'B', 'C' ]
// , [ 'A' ]
// , [ 'A', 'C' ]
// , [ 'A', 'B' ]
// , [ 'A', 'B', 'C' ]
// ]
On peut aussi passer une suite personnalisée qui fait autre chose avec le résultat
console.log (combinations (['A', 'B', 'C'], combs => combs.length))
// 8
// (8 total combinations)
Le style de passage peut être utilisé avec des résultats étonnamment élégants
const first = (x, y) =>
x
const fibonacci = (n, callback = first) =>
n === 0
? callback (0, 1)
: fibonacci
( n - 1
, (a, b) => callback (b, a + b)
)
console.log (fibonacci (10)) // 55
// 55 is the 10th fibonacci number
// (0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, ...)
J'étais tellement fatigué de voir ce même extrait encore et encore, j'ai écrit ceci:
var cb = function(g) {
if (g) {
var args = Array.prototype.slice.call(arguments);
args.shift();
g.apply(null, args);
}
};
J'ai des centaines de fonctions qui font des choses comme
cb(callback, { error : null }, [0, 3, 5], true);
ou peu importe...
Je suis sceptique quant à la stratégie globale "assurez-vous que c'est fonctionnel". Les seules valeurs légitimes sont une fonction ou une fausse. Si quelqu'un passe un nombre non nul ou une chaîne non vide, qu'allez-vous faire? Comment ignorer le problème le résout-il?
Une fonction valide est basée sur le prototype Function, utilisez:
if (callback instanceof Function)
pour être sûr que le rappel est une fonction
Si le critère pour exécuter le rappel est que ce soit défini ou non, alors ça va. Aussi, je suggère de vérifier si c'est vraiment une fonction en plus.
Cela peut facilement être fait avec ArgueJS :
function save (){
arguments = __({callback: [Function]})
.....do stuff......
if(arguments.callback){
callback();
};
};
Je me suis sincèrement déplacé vers le script de café et j'ai trouvé que les arguments par défaut étaient une bonne façon de résoudre ce problème
doSomething = (arg1, arg2, callback = ()->)->
callback()