靜態型別 vs. 動態型別 === JavaScript 是動態型別 + 弱型別。 > - [資料型態:「靜態/動態語言」和「強/弱型別」](https://hackmd.io/kAhsDwsDROuCNOIMLiNLbQ?view) > - 靜態型別 vs. 動態型別 > - [強型別 vs. 弱型別](https://hackmd.io/DZhvFyzJQF-k1Wx-HT_KfQ?view) > - [型別安全的脆弱:JavaScript 是動態型別 + 弱型別](https://hackmd.io/YFxGJTpAQRuk4AoKSX7wLQ?view) 靜態型別 --- 以 Java 為例:在宣告時,已使用 `int` 宣告 x 是整數,在日後若改變其型別,將會報錯。 ```java int x; // 使用 int 宣告 x 是整數。 x = "Hello"; // error: incompatible types: String cannot be converted to int ``` **靜態型別**: 語法撰寫時要求對變數型別有明確定義,一旦有變數誤用或資料型態上的 Bug,在編譯時期就能發現,降低執行時期的風險。編譯式語言多半是靜態語言,Java 和 C# 是其中的代表。 - 型別檢查(Type Checking)發生在編譯時期(Compile Time)。 - 程式撰寫時,必須使用明確的型別宣告。 - 型別一旦宣告,在執行時期無法任意更換型別,否則會發生錯誤。 動態型別 --- 以 Lua 為例:宣告時不需要指定明確的型別,執行過程中更改資料型態,仍可以運作。 ```lua local x -- 使用 local 宣告變數 x 時,沒有明確指定 x 的型別 x = 123 print(x) x = "Hello" -- 能夠放入任意型別,就算中間一度改變指派值的資料型態,仍可運作 print(x) ``` **動態型別**: 在程式編寫時,不需要宣告型別,且可以在過程依需求改變型別,做到十分靈活的變數處理;但缺乏對當前變數的型別限制,無法肯定 x 變數現在是什麼型別,容易造成非預期的執行結果。 在程式執行過程,進行資料型態的檢查或確認,因此直譯式語言通常是動態語言,例如 Python、PHP、Ruby、JavaScript。 - 型別檢查(Type Checking)發生在執行時期(Runtime)。 - 程式撰寫時,不用明確的型別宣告。 - 執行時,變數能任意更換型別。 隱性型別(implicity typed)的靜態語言 --- 宣告時沒有指定型別,就是動態型別?這是錯誤的,因為也有部分靜態語言,不需要指定型別,而是透過**隱性推導**確認型別,例如 Ocaml、Haskell。 擁有動態語言在宣告語法上簡便的優點,同時保有靜態語言的穩定性。 以 C# 為例:傳統 C# 必須先宣告型別,但在 C# 4.0 導入「隱性推導」。 ```c var n = 456; // 型別是初始值的型別,n 已是整數 /* 初使化之後更改型別,導致報錯 */ n = "Hello"; // Cannot implicity convert type 'string' to 'int' ``` ```c /* 宣告時沒有初始值,導致報錯 */ var n; // Implicity-typed variables must be initialized n = 123; ``` **隱性推導**: 型別是初始值的型別,在宣告時必須被初始化,之後無法更改型別。 - 靜態語言可以分為: - 顯性型別(explicitly typed):型別是語法宣告的一部份,從語法就能得知。 - `int x;` - 隱性型別(implicity typed):型別是透過編譯過程的推導得知(隱性推導)。 - `var n = 456;`