xchrist 2016-10-08
你知道JavaScript中的每条语句、甚至表达式都有一个结果值吗?
当你在浏览器中测试代码时,经常会在控制台的输出结果的最后面多出一条,大部分为undefined,这个undefined就是一个结果值。
ES7的do表达式
先从ES7的一个提案说起吧:do表达式do{...}(注意:不是do{...}while();中的do)
var a,b,c = 3; a = do { if (true) { b = c*3; } }; a; //9 目前的浏览器暂不支持
表达式do{...}的作用就是返回它后面的语句块的结果值,功能其实和return类似,只不过return需要通过函数来封装后调用。
不过目前来说,我们还无法使用上面的功能,目前的规范是不允许我们获得语句的结果值并将其赋值给一个变量的(除了使用eval(),如var a = eval('if (true) {b = c*3;}'),a的值被赋值为eval()内的语句的结果值,不建议使用eval())。
ES5规范关于结果值的规定
现在你应该大概理解了什么是结果值了,本人翻看了ES5规范,发现JavaScript中,语句块、语句、甚至表达式都会隐式地返回一个结果值,总结如下:
结果值是语句、表达式经过逻辑运算后的值,若无逻辑(按顺序执行)则为最后一条子语句、表达式的结果值(语句可以包含子语句),简单地说它就是一个语句、表达式的“隐式的返回值”,JavaScript会计算每一条语句、表达式并返回一个结果值,而对于语句块的结果值,它是最后一条最外层语句的结果值(非嵌套的子语句)。
部分浏览器会在控制台输出一段代码的最后一条语句或语句块的结果值(本文所有代码均使用Firefox测试,不同浏览器有差别)
结果值可以为任何表达式的值,也可以为空(;、break;、continue;),为空时结果值为undefined。当结果值为空时,浏览器会忽略该语句,而打印出上一条同级的非空的语句,若仅有自身一条同级语句则打印出undefined。
特例:var变量声明语句、函数声明语句的结果值为undefined。
1、变量声明语句算法的返回值实际为表示该变量名称的字符串,但是这个值被变量语句算法屏蔽掉了(for...in循环除外),最后返回结果为undefined
2、而对于函数声明语句,它的结果值本人按规范解读为该函数对象,但浏览器显示为undefined,具体什么原因,本人还不理解(可能是因为函数只是定义,未被实际执行的原因);
3、函数执行语句的结果值为:
3.1 若有throw语句,则为throw语句的结果值
3.1 若有return语句,则为return语句的结果值
3.2 若无throw、return语句则为undefined
例子:
var a,b,c = 3; if (true) {b = c*3;} //按顺序执行到最后一条语句,输出9 ; //undefined 单独的空语句 var d = 5; //undefined 所有的var声明语句的结果值均为undefined function foo(a){ a = a+2; return a; } //undefined 函数声明语句的最终结果值也为undefined foo(1); //3 函数执行语句的结果值为函数throw、return语句的结果值,若无throw、return语句,则为undefined if(true){a=1;}else{b=2;} //1 按逻辑计算结果执行a=1;语句 { var a = 1,b = 2; if(true){a;}else{b;} //输出1,最后一条空语句会被忽略 ; } var a = 5; switch(a){ case 1: a+1; break; case 5: a+5; break; case 3: a+3; break; } //10 空的break;语句会被忽略 var a = 5; switch(a){ case 1: a+1; break; case 5: break; //执行这里,它这里无同级语句 case 3: a+3; break; } //undefined
下面来具体看看表达式的结果值有什么用:
大部分表达式只有结果值,没有副作用,如:var a = 2; var b = a + 3;,这里的表达式a+3的结果值为5,被赋值给了b。
而有副作用的表达式,如:
function foo(){ a++; } var a=0; foo(); //结果值为undefined,副作用是改变了a的值
又如:
var a = 0; var b = a++; a; //1 b; //0 var c = a++; //结果值为undefined 副作用是c被赋值了,a变成了2 var d = a++, a; //结果值为undefined,副作用是d被赋值为2,a变成了3,实际执行的是var d = a++; var d = (a++,a);//结果值为undefined,副作用是d被赋值为3,a变成了3,实际执行的是var d = ++a; function foo(){ var e = f = 1; //表达式f=1的结果值为1,1又被赋值给e } foo(); f; //1 创建了全局变量f e; //ReferenceError
赋值语句的副作用是将'='右边的表达式的结果值赋值给了左边的变量,最终整个赋值语句的结果值为变量的值,为此我们可以这样:
function foo(a){ var b; if(a&&(b = a*10;)<50){ ... } }