變數,常數介紹,變數與常數的區別

我被程式碼海扁 @codebeatme
閱讀 7:55·字數 2377·發佈 

先決條件
閱讀本節的先決條件是對值和資料型別的概念有所掌握,你可以檢視值,資料型別介紹一節來了解他們。

變數

在程式碼層面,變數可以被認為是值的儲存容器,無論是哪種語言,這樣的解釋都沒有問題。變數儲存的具體值一般是可以變化的,比如,一個關於年齡的變數,開始時為0,經過計算後可能變為100

為何使用變數?
在編寫程式碼的過程中,人們需要通過變數來存取值,這使得值具有了明確的含義,比如,這個數值表示年齡,那個數值表示物品數量。如果沒有變數,那一切會像直接操作處理器一樣,開發人員會頭疼,因為他忘記了那些數值具體表示什麽。

什麽是變數的識別碼?
變數的識別碼也就是變數在程式碼中的名稱,要使用變數就需要書寫其對應的識別碼,這是一個愚蠢的問題,如果你希望某個人應答你,當然最好是說出對方的名字。

變數指派

在讀取一個變數之前,一般需要為該變數指派,這是理所當然的,因為讀取變數中的值的先決條件是存在一個值。

對於一些語言,比如 JavaScript,如果開發人員在定義變數時,未對其進行指派,那麽該變數將獲得一個預設值。而另一些語言,比如 Python,則會把未明確指派的變數視為未定義。

在下面的 JavaScript 程式碼中,變數age被賦予預設值undefined

variables_and_constants.js
// 定義變數 age,他將獲得預設值 undefined
let age
// 顯示變數 age 的值
console.log(age)
undefined

JavaScript 中的 undefined 不表示變數不存在
JavaScript 中的undefined通常用於描述未定義,但變數的值為undefined並不代表該變數不存在,當你真的存取一個不存在的變數時,通常會導致例外狀況ReferenceError

在 JavaScript 中讀取未定義變數student,將引發例外狀況ReferenceError

variables_and_constants.js
// ERROR 變數 student 沒有被定義過,這會導致例外狀況
console.log(student)
ReferenceError: student is not defined

變數型別

變數的型別用於規定其值應有的資料型別,由於隱含轉換的存在,為變數分配的值的資料型別可以和變數的型別不同,資料型別之間的轉換將自動進行,在符合一定條件的情況下。

並非所有的程式設計語言都支援宣告變數的型別,尤其是對於非型別安全的語言,他們的變數將接受任意資料型別的值。

不指定變數型別帶來了靈活性
不指定變數型別,使得程式碼更具靈活性,變數對應的值成為了一種判斷依據,你可以根據值的資料型別,來決定接下來的操作。當然,這樣的做法帶來了安全隱患,變數中的值可能是不希望或無法處理的型別。

變數種類

依據其值是儲存在堆疊還是堆積中,變數可以分為實值型別變數和參考型別變數。而從儲存值這一功能來看,參數,欄位也應被歸入變數這一概念。你可以將參數理解為函式擁有的變數,將欄位理解為類別或執行個體擁有的變數。

堆疊,堆積
想要詳細了解堆疊,堆積,實值型別變數,參考型別變數等概念,你可以檢視堆疊,堆積,指針介紹一節或堆積和參考一段。

函式是一種特殊的變數?
程式設計語言維護了一個或多個關於識別碼的“表格”,他不僅包括了變數名稱,還包括函式的名稱,通過這些“表格”,可以判斷某個變數或函式是否未定義。從這個角度來看,函式也是一種變數,只不過這種變數儲存了比較特殊的值,他們是處理資料的某種功能。

這解釋了為什麽在不少語言中,可以將函式指派給變數,或將函式作為參數傳遞。

在 JavaScript 中,我們將函式sendToClient指派給變數fn,並通過fn呼叫了該函式。

variables_and_constants.js
// 一個將資訊傳送給客戶的函式
function sendToClient(message) {
	console.log(`傳送給客戶:${message}`)
}

// 將函式 sendToClient 指派給變數 fn let fn = sendToClient // 通過變數呼叫函式 fn('今天天氣不錯!')
傳送給客戶:今天天氣不錯!

變數的傳遞

當你將一個變數指派給另一個變數時,預設會發生傳值,這使得兩個變數是相對獨立的。至於傳址,他會使一個變數成為另一個變數的別名。

堆疊,堆積
想要更好的了解傳值和傳址,你可以檢視堆疊,堆積,指針介紹一節或堆積和參考一段。

常數

與變數相反,常數似乎對應了無法改變,在程式碼中你不能對已經指派的常數再次指派,除非將其重新定義,如果允許的話。

需要指出,你不能將常數視為變數的一種特例,因為在某些情況下,常數並不會真實的儲存值。

編譯階段常數

如果一個常數的值,在編譯階段可以確定,那麽該常數被稱為編譯階段常數。編譯階段常數在真實的執行過程中是不存在的,他們僅作為一種預留位置而存在,並在編譯階段被取代為其值的常值。

當然,某個運算式能否被運算為確定的值,需要視語言對應的編譯器而定。

在下面的 C# 程式碼中,A1是一個正確的編譯階段常數,因為13可以在編譯階段確定。A2同樣是一個正確的編譯階段常數,因為運算式13+A1可以在編譯階段計算出確定結果。A3是一個不正確的編譯階段常數,因為變數b1的值無法在編譯階段確定。

*.cs
// A1 是編譯階段常數
const int A1 = 13;

// A2 是編譯階段常數,因為運算式可以在編譯階段計算出結果 const int A2 = 13 + A1;
int b1 = 0; // ERROR A3 是一個錯誤的編譯階段常數,因為 b1 的值在編譯階段是無法確定的 const int A3 = b1;

什麽是編譯階段?
編譯階段是指正在編譯的時候,而所謂的編譯,是指將程式碼轉換為可被目標執行的內容。這裏的目標可以是作業系統,或某種語言的執行環境,比如,Java 虛擬機器。

根據目標的不同,編譯內容會擁有不同的檔案格式,比如,Windows 的可執行檔案,或 Java 虛擬機器的位元組碼檔案等。

執行階段常數

與編譯階段常數不同,執行階段常數的值不需要在編譯階段確定,因此,執行階段常數更像是一種唯讀的變數,他存在於真實執行程序,並儲存真實的值。

在下面的 JavaScript 程式碼中,result是一個執行階段常數,其值由執行過程中的xy的值確定。

variables_and_constants.js
for (let x = 0; x < 2; x++)
	for (let y = 0; y < 2; y++) {
		// 執行階段常數,其值在執行階段確定
		const result = x * y

console.log(result) }
0
0
0
1

程式碼

variables_and_constants.js·codebeatme/programming·GitHub
variables_and_constants.cs·codebeatme/programming·GitHub