雖然文章標題是『語句與表達式』,在這篇文章中,我將陳述一個觀點?**每個表達式都有一個值**。 在此之外,也會繼續表述這個『[代碼之謎](http://justjavac.com/codepuzzle/2012/09/25/codepuzzle-introduction.html)』系列的主題——數學與計算機之間被經常忽略的矛盾。
簡單的講
* "表達式"(expression)是一個單純的運算過程,總是有返回值;
* "語句"(statement)是執行某種操作,沒有返回值。
使用表達式也是函數式編程語言所提倡的,而傳統命令式編程語言都是語句的堆砌。
表達式和語句如何區分呢? 最簡單最直觀的鑒別方法就是,?**后面有分號的是語句**, 這是一個充分條件而不是必要條件。 有分號,就是語句;沒有分號,就不一定了,也可能是語句,也可能是表達式。
在動態語言——比如javascript——中是通過上下文來區分這兩者的。
假如如果?`function foo(){}`?在一個賦值表達式的一部分,則認為它是一個表達式。?**表達式的一部分,也是表達式**。 而如果?`function foo(){}`?被包含在一個函數體內,或者位于程序中,則將它作為一個語句。
~~~
function foo(){}; // 聲明,因為它是程序的一部分
var bar = function foo(){}; // 表達式,因為它是賦值表達式的一部分
new function bar(){}; // 表達式,因為它是New表達式的一部分
(function(){
function bar(){}; // 聲明,因為它是函數體的一部分
})();
~~~
還有一種不那么顯而易見的表達式,就是被包含在一對圓括號中——?`(function foo(){})`。 將這種形式看成表達式同樣是因為上下文的關系: (和)構成一個分組操作符,而?**分組操作符只能包含表達式**:
~~~
(function foo(){}); // 函數表達式:注意它被包含在分組操作符中
(var x = 5); // error! 分組操作符只能包含表達式,不能包含語句(這里的var就是語句)
~~~
今天突然有人問我:
~~~
alert(eval(data));
~~~
為什么會報錯呢?data 是一個對象,按理說應該會彈出 Object[Object] 啊。 這是因為,當我們寫
~~~
{"username" : "justjavac"}
~~~
時,它并不是一個對象。 因為我們知道有一種表示數據的方法叫做 json(javascript對象表示法), 所以想當然的認為這應該是一個對象。 其實,在大部分編程語言中,大括號({})表示的不是對象,而是代碼塊,這段代碼其實等價于
~~~
{
"username" : "justjavac"
}
~~~
很顯然,`"username" : "justjavac"`?并不是合法的語句。 然而解決方法也很簡單,就是添加括號——分組操作符
~~~
({"username" : "justjavac"})
~~~
這樣就構成了一個合法的表達式,當我們進行 json 對象解析的時候可以寫如下代碼:
~~~
eval('(' + json + ')')
~~~
**在表達式中,只能存在表達式,不能存在語句。**
例如表達式
~~~
(var a = 4) + 4;
~~~
這段代碼將產生一個錯誤,因為?`var a = 4`?是一個語句, 而不是表達式——?**對表達式求值必須返回值,但對語句求值則未必有返回值**。
類似的
~~~
if (var a = 0) {}
~~~
也產生錯誤,因為?`var a = 0`?是一條語句,而?**語句沒有返回值**。if 語句的語法結構為
~~~
if (expression) {
statement;
statement;
……
}
~~~
因此
~~~
if (var a = 0) {}
~~~
是錯誤的,但是
~~~
if (true) {
var a = 0;
}
~~~
則是正確的。
最后重申一下,**每個表達式都有一個值**。 理解了這個,就可以很容易的理解 FP(函數式編程)的一些核心思想了。