對程式設計的一些感悟
從2002年接觸C語言開始,不知不覺程式設計已經伴隨我14年了,這期間或多或少的使用了C,C++,C#,Java,PHP,JavaScript, bash, VBA這些常見的開發語言,可悲的是才疏學淺,只是略懂而已。
1 程式設計的本質沒變
程式=資料結構+演算法,這是對程式最本質的、最切中要害的、最簡潔的闡述。
一直以來,我有一個習慣,就是在理解一個抽象概念的時候,一定要找到這個概念的一個具體實現。資料結構和演算法就是抽象的概念,我們不妨用C系語言的具體實現來重新定義程式,那就是:程式=結構體+函式。
資料結構和演算法是彼此影響的,在設計的時候,很難嚴格的分階段進行。如果說那個更重要,我會毫不猶豫的說:資料結構要比演算法重要!
在機器指令級別上,大多數機器都為函式定義、呼叫(CALL指令)、資料結構定義提供了直接的支援。
資料結構和演算法的結合方式,造就了形形色色的程式語言和程式設計思想。
2 純面向物件
純面向物件把演算法、資料結構進行了兩方面的彼此聯絡。
(1)函式必須施加到特定的資料結構上
任何一個函式的內部,都可以通過一個特定的指標(如this)來得到要對齊進行操作的資料結構。
(2)函式(地址)本身就是資料結構的成員
任何一個函式都被一個數據結構的成員引用,沒有獨立存在的函式。
Java,JavaScript,C#就是純面向物件的語言,在這些語言裡,(1)函式一定是成員函式;(2)函式內部一定有一個指向資料結構的指標。
在使用純面向物件的語言進行程式設計時:
(1)每定義一個函式時,首先要確定這個函式是哪個類(或者物件)的成員;
(2)每呼叫一個函式時,首先要確定函式內的this指標到底指向了哪個物件。
在使用JavaScript時,注意:一個物件的成員函式內的this指標可能指向另外一個物件。
<script type="text/javascript">
var a = {
name: "a",
f: function(){
alert(this.name);
}
};
var b = {name: "b"};
a.f.apply(b);
</script>
3 基於類與基於原型
面向物件的實現主要有兩種方式,一是基於類、二是基於原型。
C++,JAVA,PHP等採用的是基於類的實現方式,在這些語言裡,使用物件之前必須要定義描述物件的型別。在這種方式下,子類物件擁有父類物件的完整副本,父類物件、多個子類物件、彼此獨立。
#include <stdio.h>
class A
{
public:
int x;
};
class B : public A
{
};
int main()
{
A a;
a.x = 10;
B b;
b.x = 20;
printf("%d,%d\n", a.x, b.x);
return 0;
}
在基於類的語言中,只有父類子類的概念,沒有父物件、子物件的概念。
JavaScript則採用了基於基於原型的方式。在JavaScript裡,沒有類的概念,任何一個物件內部都有一個指向父物件的指標proto。子物件只是包含了父物件的指標,並沒有父物件的副本。所有的子物件共享一份父物件。
<script type="text/javascript">
var a = {};
var b = {};
a.__proto__.x = 10;
alert(b.x);
alert(Object.x);
</script>
在基於原型的語言中,沒有類的概念,只有父物件、子物件的概念。
4 靜態型別和動態型別
傳統的C/C++是靜態型別語言的典型代表,對於編譯型語言來說,編譯時(程式執行之前)必須確定資料的型別,所以只能採用靜態型別。
PHP,JavaScript則是動態型別語言,大多數解釋性語言都採用動態型別。執行時由直譯器負責根據實際的資料來確定儲存的具體型別。
無論靜態型別還是動態型別的語言,其程式在執行的時候,任何資料都必須是確定的型別。
5 執行時可變的資料結構
JavaScript的物件屬性、陣列元素可以在執行時動態增減,PHP的物件成員、陣列元素也可以執行時動態增減。這種執行時可變的資料結構給程式設計帶來了很大的便利。雜湊表是實現這種可變資料結構的關鍵。