大多數情況下,JavaScript 應用需要處理信息。這有兩個例子:
壹個網上商店 —— 這裏的信息可能包含正在售賣的商品和購物車。
壹個聊天應用 —— 這裏的信息可能包括用戶和消息等等。
變量就是用來儲存這些信息的。
變量 是數據的“命名存儲”。我們可以使用變量來保存商品、訪客和其他信息。
在 JavaScript 中創建壹個變量,我們需要用到 let
關鍵字。
下面的語句創建(也可以稱爲 聲明 或者 定義)了壹個名稱爲 “message” 的變量:
let message;
現在,我們可以通過賦值運算符 =
爲變量添加壹些數據:
let message; message = 'Hello'; // 將字符串 'Hello' 保存在名爲 message 的變量中
現在這個字符串已經保存到與該變量相關聯的內存區域了,我們可以通過使用該變量名稱訪問它:
let message; message = 'Hello!'; alert(message); // 顯示變量內容
簡潔壹點,我們可以將變量定義和賦值合並成壹行:
let message = 'Hello!'; // 定義變量,並且賦值 alert(message); // Hello!
也可以在壹行中聲明多個變量:
let user = 'John', age = 25, message = 'Hello';
看上去代碼長度更短,但並不推薦這樣。爲了更好的可讀性,請壹行只聲明壹個變量。
多行變量聲明有點長,但更容易閱讀:
let user = 'John'; let age = 25; let message = 'Hello';
壹些程序員采用下面的形式書寫多個變量:
let user = 'John', age = 25, message = 'Hello';
……甚至使用“逗號在前”的形式:
let user = 'John' , age = 25 , message = 'Hello';
技術上講,這些變體都有壹樣的效果。所以,這是個個人品味和審美方面的問題。
var
而不是 let
在較老的腳本中,妳也可能發現另壹個關鍵字 var
,而不是 let
:
var message = 'Hello';
var
關鍵字與 let
大體 相同,也用來聲明變量,但稍微有些不同,也有點“老派”。
let
和 var
之間有些微妙的差別,但目前對于我們來說並不重要。我們將會在 老舊的 "var" 章節中介紹它們。
如果將變量想象成壹個“數據”的盒子,盒子上有壹個唯壹的標注盒子名字的貼紙。這樣我們能更輕松地掌握“變量”的概念。
例如,變量 message
可以被想象成壹個標有 "message"
的盒子,盒子裏面的值爲 "Hello!"
:
我們可以在盒子內放入任何值。
並且,這個盒子的值,我們想改變多少次,就可以改變多少次:
let message; message = 'Hello!'; message = 'World!'; // 值改變了 alert(message);
當值改變的時候,之前的數據就被從變量中刪除了:
我們還可以聲明兩個變量,然後將其中壹個變量的數據拷貝到另壹個變量。
let hello = 'Hello world!'; let message; // 將字符串 'Hello world' 從變量 hello 拷貝到 message message = hello; // 現在兩個變量保存著相同的數據 alert(hello); // Hello world! alert(message); // Hello world!
聲明兩次會觸發 error
壹個變量應該只被聲明壹次。
對同壹個變量進行重複聲明會觸發 error:
let message = "This"; // 重複 'let' 會導致 error let message = "That"; // SyntaxError: 'message' has already been declared
因此,我們對同壹個變量應該只聲明壹次,之後在不使用 let
的情況下對其進行引用。
函數式語言
有趣的是,也存在禁止更改變量值的 函數式 編程語言。比如 Scala 或 Erlang。
在這種類型的語言中,壹旦值保存在盒子中,就永遠存在。如果妳試圖保存其他值,它會強制創建壹個新盒子(聲明壹個新變量),無法重用之前的變量。
雖然第壹次看上去有點奇怪,但是這些語言有很大的發展潛力。不僅如此,在某些領域,比如並行計算,這個限制有壹定的好處。研究這樣的壹門語言(即使不打算很快就用上它)有助于開闊視野。
JavaScript 的變量命名有兩個限制:
變量名稱必須僅包含字母、數字、符號 $
和 _
。
首字符必須非數字。
有效的命名,例如:
let userName; let test123;
如果命名包括多個單詞,通常采用駝峰式命名法(camelCase)。也就是,單詞壹個接壹個,除了第壹個單詞,其他的每個單詞都以大寫字母開頭:myVeryLongName
。
有趣的是,美元符號 '$'
和下劃線 '_'
也可以用于變量命名。它們是正常的符號,就跟字母壹樣,沒有任何特殊的含義。
下面的命名是有效的:
let $ = 1; // 使用 "$" 聲明壹個變量 let _ = 2; // 現在用 "_" 聲明壹個變量 alert($ + _); // 3
下面的變量命名不正確:
let 1a; // 不能以數字開始 let my-name; // 連字符 '-' 不允許用于變量命名
區分大小寫
命名爲 apple
和 APPLE
的變量是不同的兩個變量。
允許非英文字母,但不推薦
可以使用任何語言,包括西裏爾字母(cyrillic letters)甚至是象形文字,就像這樣:
let имя = '...'; let 我 = '...';
從技術上講,這樣沒問題。這樣的命名是完全允許的,但是用英文進行變量命名是國際慣例。哪怕我們正在寫壹個很小的腳本,它也有可能會被使用很久。某個時候,來自其他國家的人可能會需要閱讀它。
保留字
有壹張 保留字列表,這張表中的保留字無法用作變量命名,因爲它們被用于編程語言本身了。
比如,let
、class
、return
、function
都被保留了。
下面的代碼將會抛出壹個語法錯誤:
let let = 5; // 不能用 "let" 來命名壹個變量,錯誤! let return = 5; // 同樣,不能使用 "return",錯誤!
未采用 use strict
下的賦值
壹般,我們需要在使用壹個變量前定義它。但是在早期,我們可以不使用 let
進行變量聲明,而可以簡單地通過賦值來創建壹個變量。現在如果我們不在腳本中使用 use strict
聲明啓用嚴格模式,這仍然可以正常工作,這是爲了保持對舊腳本的兼容。
// 注意:這個例子中沒有 "use strict" num = 5; // 如果變量 "num" 不存在,就會被創建 alert(num); // 5
上面這是個糟糕的做法,嚴格模式下會報錯。
"use strict"; num = 5; // 錯誤:num 未定義
聲明壹個常數(不變)變量,可以使用 const
而非 let
:
const myBirthday = '18.04.1982';
使用 const
聲明的變量稱爲“常量”。它們不能被修改,如果妳嘗試修改就會發現報錯:
const myBirthday = '18.04.1982'; myBirthday = '01.01.2001'; // 錯誤,不能對常量重新賦值
當程序員能確定這個變量永遠不會改變的時候,就可以使用 const
來確保這種行爲,並且清楚地向別人傳遞這壹事實。
壹個普遍的做法是將常量用作別名,以便記住那些在執行之前就已知的難以記住的值。
使用大寫字母和下劃線來命名這些常量。
例如,讓我們以所謂的“web”(十六進制)格式爲顔色聲明常量:
const COLOR_RED = "#F00"; const COLOR_GREEN = "#0F0"; const COLOR_BLUE = "#00F"; const COLOR_ORANGE = "#FF7F00"; // ……當我們需要選擇壹個顔色 let color = COLOR_ORANGE; alert(color); // #FF7F00
好處:
COLOR_ORANGE
比 "#FF7F00"
更容易記憶。
比起 COLOR_ORANGE
而言,"#FF7F00"
更容易輸錯。
閱讀代碼時,COLOR_ORANGE
比 #FF7F00
更易懂。
什麽時候該爲常量使用大寫命名,什麽時候進行常規命名?讓我們弄清楚壹點。
作爲壹個“常數”,意味著值永遠不變。但是有些常量在執行之前就已知了(比如紅色的十六進制值),還有些在執行期間被“計算”出來,但初始賦值之後就不會改變。
例如:
const pageLoadTime = /* 網頁加載所需的時間 */;
pageLoadTime
的值在頁面加載之前是未知的,所以采用常規命名。但是它仍然是個常量,因爲賦值之後不會改變。
換句話說,大寫命名的常量僅用作“硬編碼(hard-coded)”值的別名。
談到變量,還有壹件非常重要的事。
壹個變量名應該有壹個清晰、明顯的含義,對其存儲的數據進行描述。
變量命名是編程過程中最重要且最複雜的技能之壹。快速地浏覽變量的命名就知道代碼是壹個初學者還是有經驗的開發者寫的。
在壹個實際項目中,大多數的時間都被用來修改和擴展現有的代碼庫,而不是從頭開始寫壹些完全獨立的代碼。當壹段時間後,我們做完其他事情,重新回到我們的代碼,找到命名良好的信息要容易得多。換句話說,變量要有個好名字。
聲明變量之前,多花點時間思考它的更好的命名。妳會受益良多。
壹些可以遵循的規則:
使用易讀的命名,比如 userName
或者 shoppingCart
。
離諸如 a
、b
、c
這種縮寫和短名稱遠壹點,除非妳真的知道妳在幹什麽。
變量名在能夠准確描述變量的同時要足夠簡潔。不好的例子就是 data
和 value
,這樣的名稱等于什麽都沒說。如果能夠非常明顯地從上下文知道數據和值所表達的含義,這樣使用它們也是可以的。
腦海中的術語要和團隊保持壹致。如果網站的訪客稱爲“用戶”,則我們采用相關的變量命名,比如 currentUser
或者 newUser
,而不要使用 currentVisitor
或者壹個 newManInTown
。
聽上去很簡單?確實如此,但是在實踐中選擇壹個壹目了然的變量名稱並非如此簡單。大膽試試吧。
重用還是新建?
最後壹點,有壹些懶惰的程序員,傾向于重用現有的變量,而不是聲明壹個新的變量。
結果是,這個變量就像是被扔進不同東西盒子,但沒有改變它的貼紙。現在裏面是什麽?誰知道呢。我們需要靠近壹點,仔細檢查才能知道。
這樣的程序員節省了壹點變量聲明的時間,但卻在調試代碼的時候損失數十倍時間。
額外聲明壹個變量絕對是利大于弊的。
現代的 JavaScript 壓縮器和浏覽器都能夠很好地對代碼進行優化,所以不會産生性能問題。爲不同的值使用不同的變量可以幫助引擎對代碼進行優化。
我們可以使用 var
、let
或 const
聲明變量來存儲數據。
let
— 現代的變量聲明方式。
var
— 老舊的變量聲明方式。壹般情況下,我們不會再使用它。但是,我們會在 老舊的 "var" 章節介紹 var
和 let
的微妙差別,以防妳需要它們。
const
— 類似于 let
,但是變量的值無法被修改。
變量應當以壹種容易理解變量內部是什麽的方式進行命名。
重要程度: 2
聲明兩個變量:admin
和 name
。
將值 "John"
賦給 name
。
從 name
變量中拷貝其值給 admin
。
使用 alert
顯示 admin
的值(必須輸出 “John”)。
下面的代碼,每壹行都對應著任務列表中的對應項。
let admin, name; // 壹次聲明兩個變量。 name = "John"; admin = name; alert( admin ); // "John"
重要程度: 3
使用我們的星球的名字創建壹個變量。妳會怎麽命名這個變量?
創建壹個變量來存儲當前浏覽者的名字。妳會怎麽命名這個變量?
這很簡單:
let ourPlanetName = "Earth";
注意,我們也可以用壹個更簡短的名字 planet
,但這樣可能並不能表達清楚它指的是哪個星球。再啰嗦壹點也挺好的。至少讓這個變量別太長就行。
let currentUserName = "John";
同樣,如果我們的確知道用戶就是當前的用戶的話,我們可以使用更短的變量名 userName
。
現代編輯器的自動補全可以讓長變量名變得容易編寫。不要浪費這個特性。壹個名字中包含三個詞挺好的。
如果妳的編輯器沒有合適的自動補全功能,換 壹個新的吧。
重要程度: 4
檢查下面的代碼:
const birthday = '18.04.1982'; const age = someCode(birthday);
這裏我們有壹個 birthday
日期常量和通過壹些代碼(爲了保持簡短這裏沒有提供,因爲這些細節在這無關緊要)從 birthday
計算出的 age
常量。
對于 birthday
使用大寫方式正確嗎?那麽 age
呢?或者兩者都用?
const BIRTHDAY = '18.04.1982'; // 使用大寫? const AGE = someCode(BIRTHDAY); // 使用大寫?
我們通常用大寫字母表示“硬編碼(hard-coded)”的常量。或者,換句話說就是,當值在執行之前或在被寫入代碼的時候,我們就知道值是什麽了。
在這個代碼中 birthday
確實是這樣的。因此我們可以使用大寫。
在對照組中,age
是在程序運行時計算出的。今天我們有壹個年齡,壹年以後我們就會有另壹個。它在某種意義上不會隨著代碼的執行而改變。但與 birthday
相比,它還是有壹定的可變性:它是計算出來的,因此我們應該使用小寫。