但是'return'本身的实际类型是什么呢。
'return'没有类型,它不是一个值。
尝试使用typeof return;
会得到Unexpected token return
。
那么,我们可以将逗号分隔的表达式传递到return语句中。这是一个函数吗?
不是,虽然括号可以用于调用函数,但这里它们是包含了几个由逗号运算符分隔的表达式的分组运算符。
一个更有用的示例是:
function add(a, b) {
return (
(a + b),
(a - b)
);
}
console.log(add(2, 2));
执行结果为0
,因为a + b
的结果被忽略了(它在逗号运算符的LHS上),而返回的是a - b
。
return
语句看不到它们,这就是您所询问的内容。 - Quentina + b
没有显著影响,因为它没有副作用并且值被舍弃了(虽然考虑到它没有实际影响,优化编译器可能会将其删除,但这并没有实际影响)。 - Quentinif
一样,跳过某个表达式不执行的唯一方法是短路运算。逗号操作符不会短路,因此它将计算两侧并返回最后一个。这是逗号操作符的明确目的,将表达式分组在单个语句中(通常忽略整个语句的结果值),最常用于变量初始化:var i = 2, j = 3, k=4;
- Jason我有点震惊,这里没人直接引用规范:
12.9 return语句 语法:ReturnStatement : return ; return [不跟随行终止符] Expression ;
语义
如果 ECMAScript 程序中包含一个不在函数体内的 return 语句,则认为该程序在语法上不正确。return 语句导致函数停止执行并将一个值返回给调用者。如果省略 Expression,则返回值为 undefined。否则,返回值就是 Expression 的值。
ReturnStatement 的求值如下:
如果没有 Expression 存在,返回
(return, undefined, empty)
。 让exprRef
成为评估表达式的结果。 返回(return, GetValue(exprRef), empty)
。
因此,根据规范,您的示例应该写成:
return ( GetValue(exprRef) )
其中
exprRef = console.log(a + b), console.log(arguments)
根据逗号运算符的规范...
语义
表达式:Expression,AssignmentExpression 的产生式求值如下:
...意味着每个表达式将被评估,直到逗号列表中的最后一项,成为赋值表达式。因此,您的代码Let lref be the result of evaluating Expression. Call GetValue(lref). Let rref be the result of evaluating AssignmentExpression. Return GetValue(rref).
return (console.log(a + b) , console.log(arguments))
将会:
1.) 打印出a+b
的结果。
2.) 没有剩余的表达式可以执行,所以执行下一个表达式,它
3.) 打印arguments
,由于console.log()
没有指定返回语句,
4.) 将会被计算为undefined。
5.) 最终将undefined作为返回值返回给调用者。
因此,正确的答案是,return
没有类型,它只返回某些表达式的结果。
下一个问题:
“那么,我们可以通过逗号分隔的表达式传递到返回语句中。这是一个函数吗?”
不是。在JavaScript中,逗号是运算符,定义了允许您将多个表达式组合成单行的方式,并按规范定义为返回您列表中最后一个表达式的计算表达式。
您还不相信我吗?
<script> alert(foo()); function foo(){ var foo = undefined + undefined; console.log(foo); return undefined, console.log(1), 4; } </script>
在这里玩弄那段代码并且改变列表中的最后一个值。 它将始终返回列表中的最后一个值,在您的情况下,它恰好是
undefined。
对于您的最后一个问题,
从这开始,我们是否可以猜测JavaScript中的每个关键字最终都是一个函数?
同样,不是的。在语言中,函数有一个非常具体的定义。我不会在这里重印它,因为这个答案已经变得极长。
测试返回带括号的值时会发生什么:
function foo() {
return (1, 2);
}
console.log(foo());
回答是2
,因此似乎逗号分隔的值列表将评估为列表中的最后一个元素。
实际上,在这里括号是无关紧要的,它们是将操作分组而不是表示函数调用。可能令人惊讶的是,逗号在这里是合法的。我发现了一篇有趣的博客文章,介绍了逗号在这里的处理方式:
https://javascriptweblog.wordpress.com/2011/04/04/the-javascript-comma-operator/
return ([1, 2])
这样的代码将会打印出两个值? - cst1992console.log((1, 2))
- thedayturnsreturn
不是一个函数,它是出现在函数中的连续体。
想一下这个语句:alert(2 * foo(bar));
,其中foo
是一个函数的名称。当你评估它时,你会发现要暂时搁置语句的剩余部分,集中精力评估foo(bar)
。你可以将你搁置的部分视为类似于alert (2 * _)
的东西,其中有一个要填充的空白。当你知道foo(bar)
的值后,你会继续进行。
你设置的东西是调用foo(bar)
的连续体。
调用return
将一个值提供给该连续体。
当你在foo
内部评估函数时,foo
的其余部分等待该函数归约为一个值,然后foo
继续进行。你仍然有一个目标,即评估foo(bar)
,只是暂停了。
当你在foo
内部评估return
时,foo
的任何部分都不会等待一个值。在你使用return
的foo
内部,它不会归约为一个值。相反,它导致整个调用foo(bar)
归约为一个值,并且目标“评估foo(bar)
”被视为已完成并消失。
当你刚开始学习编程时,人们通常不会告诉你连续体。他们认为这是一个高级话题,仅仅是因为有些非常高级的东西最终可以用连续体来实现。但事实上,每次调用一个函数时,你始终在使用它们。
alert(2 * _)
的延续以备后用(有另一种表示法来做这种事情)。 - Cort Ammonfoo
内部的return
不是一个值; 你不能将它打包到数据结构中,分配给变量,等待一段时间然后稍后再喂它--尤其是你不能多次喂它。但是,就像我说的,这是高级话题。 - Nathan Ellis Rasmussenif()then{}else{}
完全相同的my_if
函数,即使允许在其中使用内置函数,仍然无法做到这一点--这并不是非常高级的内容,但对于你最终编写需要传递回调的代码来说,它是非常有益的学习资源。 - Nathan Ellis Rasmussenreturn
是一个转移注意力的话题。也许更有趣的是下面的变化:function add(a, b) {
return (
console.log(a + b),
console.log(arguments)
);
}
console.log(add(2, 2));
这将作为最后一行输出
undefined
由于这个函数实际上没有返回任何内容。(如果有第二个console.log
的返回值,它将返回该返回值)。
就目前而言,这段代码与以下代码完全相同:
function add(a, b) {
console.log(a + b);
console.log(arguments);
}
console.log(add(2, 2));
理解return语句的有趣方式是通过void运算符。看一下这段代码:
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" />
由于return
语句需要一个参数,即[[expression]]
,并将其返回给调用栈中的调用者,即arguments.callee.caller
,因此它将执行void(expression)
,然后返回undefined
,这是void运算符的评估结果。
var a = (2 + 2)
。 - alexmacvar a = (1, 2)
-- 这会导致a
的值为2
,因为逗号运算符的操作方式(是的,逗号像+
或|
等数学运算符一样,在λ演算中,逗号运算符实现了 K 组合子)。 - slebetman