---
# System prepended metadata

title: 靜態型別 vs. 動態型別

---

靜態型別 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;`

