Nous utilisons les instructions return facultativement dans les fonctions JavaScript. C'est un mot-clé. Mais quel est le type réel de return
lui-même. En fait, je me suis perdu, en voyant l'exemple:
function add(a, b) {
return (
console.log(a + b),
console.log(arguments)
);
}
add(2, 2);
Sortie:
4
[2, 2]
Ainsi, nous pouvons passer des expressions séparées par des virgules dans l'instruction return
. Est-ce une fonction?
Et à partir de là, pouvons-nous deviner que tous les mots clés de JavaScript sont finalement une fonction?
J'ai écrit un petit blog comme un résumé de cette discussion. Vous voudrez peut-être le vérifier ici .
Mais quel est le type réel de "retour" lui-même.
Il n'a pas de type, ce n'est pas une valeur.
Tentative typeof return;
te donnera Unexpected token return
.
Ainsi, nous pouvons passer des expressions séparées par des virgules dans l'instruction de retour. Est-ce une fonction?
Non, alors que les parenthèses peuvent être utilisées pour appeler une fonction, elles sont ici un opérateur de regroupement contenant quelques expressions séparées par un opérateur virgule .
Une démonstration plus utile serait:
function add(a, b) {
return (
(a + b),
(a - b)
);
}
console.log(add(2, 2));
Quelles sorties 0
car le résultat de a + b
est ignoré (il se trouve sur le LHS de l'opérateur virgule) et a - b
est retourné.
Je suis un peu choqué que personne ici n'ait directement référencé la spécification :
12.9 La syntaxe de l'instruction return ReturnStatement: return; return [pas de LineTerminator ici] Expression;
Sémantique
Un programme ECMAScript est considéré comme syntaxiquement incorrect s'il contient une instruction de retour qui n'est pas dans un FunctionBody. Une instruction return oblige une fonction à cesser son exécution et à renvoyer une valeur à l'appelant. Si Expression est omis, la valeur de retour n'est pas définie. Sinon, la valeur de retour est la valeur de Expression.
Un ReturnStatement est évalué comme suit:
Si l'expression n'est pas présente, retournez
(return, undefined, empty)
. SoitexprRef
le résultat de l'évaluation de l'expression. Retournez(return, GetValue(exprRef), empty)
.
Donc, à cause de la spécification, votre exemple se lit comme suit:
return ( GetValue(exprRef) )
où exprRef = console.log(a + b), console.log(arguments)
Selon le spécification sur l'opérateur virgule ...
Sémantique
L'expression de production: Expression, AssignmentExpression est évaluée comme suit:
Let lref be the result of evaluating Expression. Call GetValue(lref). Let rref be the result of evaluating AssignmentExpression. Return GetValue(rref).
... signifie que chaque expression sera évaluée jusqu'au dernier élément de la liste des virgules, qui devient l'expression d'affectation. Donc, votre code return (console.log(a + b) , console.log(arguments))
va
1.) imprimez le résultat de a + b
2.) Il ne reste rien à exécuter, donc exécutez l'expression suivante qui
3.) affiche le arguments
, et parce que console.log()
ne spécifie pas de déclaration de retour
4.) Évalue à indéfini
5.) Qui est ensuite retourné à l'appelant.
La bonne réponse est donc que return
n'a pas de type, il ne renvoie que le résultat d'une expression.
Pour la question suivante:
Ainsi, nous pouvons passer des expressions séparées par des virgules dans l'instruction de retour. Est-ce une fonction?
Non. La virgule en JavaScript est un opérateur, défini pour vous permettre de combiner plusieurs expressions en une seule ligne, et est défini par la spécification pour renvoyer l'expression évaluée de ce qui est le dernier de votre liste.
Tu ne me crois toujours pas?
<script>
alert(foo());
function foo(){
var foo = undefined + undefined;
console.log(foo);
return undefined, console.log(1), 4;
}
</script>
Jouez avec ce code ici et jouez avec la dernière valeur de la liste. Il renverra toujours la dernière valeur de la liste, dans votre cas, il se trouve juste être undefined.
Pour votre dernière question,
Et à partir de là, pouvons-nous deviner que tous les mots clés de JavaScript sont finalement une fonction?
Encore une fois, non. Les fonctions ont une définition très spécifique dans la langue. Je ne le réimprimerai pas ici car cette réponse devient déjà extrêmement longue.
Test de ce qui se passe lorsque vous renvoyez des valeurs entre parenthèses:
function foo() {
return (1, 2);
}
console.log(foo());
Donne la réponse 2
, il apparaît donc qu'une liste de valeurs séparées par des virgules correspond au dernier élément de la liste.
Vraiment, les parenthèses ne sont pas pertinentes ici, elles regroupent des opérations au lieu de signifier un appel de fonction. Ce qui est peut-être surprenant, cependant, c'est que la virgule est légale ici. J'ai trouvé un article de blog intéressant sur la façon dont la virgule est traitée ici:
https://javascriptweblog.wordpress.com/2011/04/04/the-javascript-comma-operator/
return
n'est pas une fonction. C'est le suite de la fonction dans laquelle il se produit.
Pensez à l'instruction alert (2 * foo(bar));
où foo
est le nom d'une fonction. Lorsque vous l'évaluez, vous voyez que vous devez mettre de côté le reste de l'instruction pendant un moment pour vous concentrer sur l'évaluation de foo(bar)
. Vous pouvez visualiser la pièce que vous mettez de côté comme quelque chose comme alert (2 * _)
, avec un blanc à remplir. Lorsque vous savez quelle est la valeur de foo(bar)
, vous la récupérez.
La chose que vous avez mise de côté était le suite de l'appel foo(bar)
.
L'appel de return
alimente une valeur à cette continuation.
Lorsque vous évaluez une fonction à l'intérieur de foo
, le reste de foo
attend que cette fonction soit réduite à une valeur, puis foo
reprend . Vous avez toujours un objectif pour évaluer foo(bar)
, c'est juste une pause.
Lorsque vous évaluez return
dans foo
, aucune partie de foo
n'attend une valeur. return
ne se réduit pas à une valeur à l'intérieur de foo
où vous l'avez utilisé. Au lieu de cela, il entraîne la réduction de la valeur de callfoo(bar)
dans son intégralité, et l'objectif "evaluer foo(bar)
" est considéré comme terminé et est supprimé.
Les gens ne vous parlent généralement pas des suites lorsque vous débutez en programmation. Ils le considèrent comme un sujet avancé, juste parce qu'il y a sont des choses très avancées que les gens finissent par faire avec des continuations. Mais la vérité est que vous les utilisez depuis le début, chaque fois que vous appelez une fonction.
le return
voici un hareng rouge. Peut-être intéressant est la variation suivante:
function add(a, b) {
return (
console.log(a + b),
console.log(arguments)
);
}
console.log(add(2, 2));
qui sort comme dernière ligne
undefined
car la fonction ne retourne rien. (Il retournerait la valeur de retour du second console.log
, s'il en avait un).
En l'état, le code est exactement identique à
function add(a, b) {
console.log(a + b);
console.log(arguments);
}
console.log(add(2, 2));
Une façon intéressante de comprendre l'instruction return est d'utiliser l'opérateur void Jetez un œil à ce code
var console = {
log: function(s) {
document.getElementById("console").innerHTML += s + "<br/>"
}
}
function funReturnUndefined(x,y) {
return ( void(x+y) );
}
function funReturnResult(x,y) {
return ( (x+y) );
}
console.log( funReturnUndefined(2,3) );
console.log( funReturnResult(2,3) );
<div id="console" />
Étant donné que l'instruction return
prend un argument qui est [[expression]]
Et le renvoie à l'appelant sur la pile, c'est-à-dire arguments.callee.caller
, Il exécutera alors void(expression)
puis retournera undefined
c'est l'évaluation de l'opérateur void.