‘ return’关键字是什么类型的?

我们在 JavaScript 函数中可选地使用 返回语句。这是个关键词。但是 return本身的实际类型是什么呢。事实上,看到这个例子,我感到很困惑:

function add(a, b) {
return (
console.log(a + b),
console.log(arguments)
);
}


add(2, 2);

产出:

4
[2, 2]

因此,我们可以将逗号分隔的表达式传递到 return语句中。这是一个函数吗?

从这里开始,我们可以大胆猜测 JavaScript 中的每个关键字最终都是一个函数吗?

我已经写了一个小博客作为这个讨论的要点。你可能想检查它 给你

7820 次浏览

But what is the actual type of 'return' itself.

It doesn't have a type, it isn't a value.

Attempting typeof return; will give you Unexpected token return.

So, we can pass comma separated expressions into the return statement. Is this a function?

No, while parenthesis can be used to call a function, here they are a grouping operator containing a couple of expressions seperated by a comma operator.

A more useful demonstration would be:

function add(a, b) {
return (
(a + b),
(a - b)
);
}


console.log(add(2, 2));

Which outputs 0 because the result of a + b is ignored (it is on the LHS of the comma operator) and a - b is returned.

Testing what happens when you return parenthesiesed values:

function foo() {
return (1, 2);
}


console.log(foo());

Gives the answer 2, so it appears that a comma separated list of values evaluates to the last element in the list.

Really, the parenthesis are irrelevant here, they're grouping operations instead of signifying a function call. What's possibly surprising, though, is that the comma is legal here. I found an interesting blog post on how the comma is deal with here:

https://javascriptweblog.wordpress.com/2011/04/04/the-javascript-comma-operator/

return is not a function. It's the continuation of the function in which it occurs.

Think about the statement alert (2 * foo(bar)); where foo is the name of a function. When you're evaluating it, you see that you have to set aside the rest of the statement for a moment to concentrate on evaluating foo(bar). You could visualize the part you set aside as something like alert (2 * _), with a blank to fill in. When you know what the value of foo(bar) is, you pick it up again.

The thing you set aside was the continuation of the call foo(bar).

Calling return feeds a value to that continuation.

When you evaluate a function inside foo, the rest of foo waits for that function to reduce to a value, and then foo picks up again. You still have a goal to evaluate foo(bar), it's just paused.

When you evaluate return inside foo, no part of foo waits around for a value. return doesn't reduce to a value at the place inside foo where you used it. Instead, it causes the entire call foo(bar) to reduce to a value, and the goal "evaluate foo(bar)" is deemed complete and blown away.

People don't usually tell you about continuations when you're new to programming. They think of it as an advanced topic, just because there are some very advanced things that people eventually do with continuations. But the truth is, you're using them all along, every time you call a function.

the return here is a red herring. Perhaps interesting ist the following variation:

function add(a, b) {
return (
console.log(a + b),
console.log(arguments)
);
}


console.log(add(2, 2));

which outputs as the last line

undefined

as the function does not actually return anything. (It would return the return value of the second console.log, if it had one).

As it is, the code is exactly identical to

function add(a, b) {
console.log(a + b);
console.log(arguments);
}


console.log(add(2, 2));

I'm kinda shocked that no one here has directly referenced the spec:

12.9 The return Statement Syntax ReturnStatement : return ; return [no LineTerminator here] Expression ;

Semantics

An ECMAScript program is considered syntactically incorrect if it contains a return statement that is not within a FunctionBody. A return statement causes a function to cease execution and return a value to the caller. If Expression is omitted, the return value is undefined. Otherwise, the return value is the value of Expression.

A ReturnStatement is evaluated as follows:

If the Expression is not present, return (return, undefined, empty). Let exprRef be the result of evaluating Expression. Return (return, GetValue(exprRef), empty).

So, because of the spec, your example reads:

return ( GetValue(exprRef) )

where exprRef = console.log(a + b), console.log(arguments)

Which according to the spec on the comma operator...

Semantics

The production Expression : Expression , AssignmentExpression is evaluated as follows:

Let lref be the result of evaluating Expression.
Call GetValue(lref).
Let rref be the result of evaluating AssignmentExpression.
Return GetValue(rref).

...means that every expression will get evaluated until the last item in the comma list, which becomes the assignment expression. So your code return (console.log(a + b) , console.log(arguments)) is going to

1.) print the result of a + b

2.) Nothing is left to execute, so execute the next expression which

3.) prints the arguments, and because console.log() doesn't specify a return statement

4.) Evaluates to undefined

5.) Which is then returned to the caller.

So the correct answer is, return doesn't have a type, it only returns the result of some expression.

For the next question:

So, we can pass comma separated expressions into the return statement. Is this a function?

No. The comma in JavaScript is an operator, defined to allow you to combine multiple expressions into a single line, and is defined by the spec to return the evaluated expression of whatever is last in your list.

You still don't believe me?

<script>
alert(foo());
function foo(){
var foo = undefined + undefined;
console.log(foo);
return undefined, console.log(1), 4;
}
</script>

Play with that code here and mess with the last value in the list. It will always return the last value in the list, in your case it just happens to be undefined.

For your final question,

And starting with this, can we take a wild guess that every keyword in JavaScript are ultimately a function?

Again, no. Functions have a very specific definition in the language. I won't reprint it here because this answer is already getting extremely long.

An interesting way to understand the return statement is through the void operator Take a look at this 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" />

Since the return statement takes one argument that is [[expression]] and return this to the caller on the stack i.e. arguments.callee.caller it will then execute void(expression) and then return undefined that is the evaluation of the void operator.