JavaScript淺嚐紀錄No.2-JS的中變數、函式的潛規則

宣告變數、賦值 (assign)

變數的作用

為什麼要使用變數,原因其實很簡單,就是為了不要重複打同樣的一大串程式碼,更簡單的說就是懶,所以創造變數讓它去記得想讓它去記得的東西(同樣的一大串程式碼)。

變數的命名是有規則的

需要注意的事項

  • 變數的名稱被稱為 identifiers 需要遵從一定的規則。
  • 可以使用錢符($)、底線(_)與數字進行命名。如 $myBirthday 或 _myBirthday
  • 可以使用英文大、小寫命名不同變數。如 MyBirthday 與 myBirthday 會被視作不同變數。
  • 名稱不可使用JavaScript語言保留字詞(w3schools中JavaScript Reserved Words的介紹)。
  • 數字不能作為變數開頭

可以怎麼幫變數命名?

變數與函式,都用小駝峰式(camelCase)的命名或大駝峰式命名法(CamelCase)命名,像是myBirthday(小駝峰式)、MyBirthday(大駝峰式),說實在我也很少看到用錢符($)、底線(_)作為變數的開頭的(或旭是因為我看的程式碼太少吧),所以還是隨眾用小駝峰式(camelCase)命名方法。

參考資料(裡面有介紹更多好的跟不好的命名,可以在詳讀。)
變數、常數與命名
變數命名規則

宣告變數

在ES6裡提出新的宣告方式letconst,但原本的var還是可以繼續使用,但已經不太建議了!這3個宣告的方式差異是甚麼?

  • var:宣告一個可隨意更改其內容的變數。
  • let:宣告一個可隨意更改其內容的區塊區域變數。
  • const:宣告一個只可讀取的不可變常數(像是 const pi = 3.14,是固定的),如果去改變用const宣告的變數的值,將會得到Assignment to constant variable.,不能對const宣告的變數的值作重新賦值的動作,但用const宣告物件,如果要改變物件裡面的屬性值是被允許的(又牽扯到資料型別的儲存方式了,有空再打)。

在上面出現了一個名詞叫作區塊區域變數,這也是為什麼varlet很相似,但不建議使用var而要改用let的原因?

全域變數v.s區域變數

全域變數 (global variable)指得是在這份程式文件裡面的所有程式碼都可以使用到這個變數。

區域變數(Local Variable)指得是變數只在宣告的區塊或函式裡面才有效(也就是在{}裡面)。

甚麼意思?比較一下下面的程式碼。

1
2
3
4
5
6
7
8
9
10
11
12
13
//var
if (true) {
var A = 5;
}
console.log(A);
console.log(this); //這個this指的是window object

//let
if (true) {
let B = 5;
}
console.log(B);
console.log(this);

if裡用var宣告的變數A,在if{}外面還能取得到值,並且利用console.log(this),查詢window object時,還能在裡面發現變數A的值,這也就是全域變數 (global variable),這也就是為什麼在MDN裡對於var有這段描述:其變數值還會超出宣告區塊而影響到全部的描述碼。

再看看let的情況有不一樣了在if裡面宣告的變數B,在if{}外面就無法取得到值了,並且利用condole.log(this)(要先刪除console.log(B)再用),查詢window object時,也找不到變數B了,這也就是區域變數(Local Variable)。

下面幾種情況很容易混淆,一定要注意:

  • function中利用var宣告變數也能產生區域變數,這似乎牽涉到function的語法作用域問題就暫時不解釋了。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
function getTotal(){
var total = 40; //區域變數
console.log(total);
}
getTotal();//40
console.log(total); //Uncaught ReferenceError: total is not defined

//比較
var total //全域變數
function getTotal(){
total = 40;
}
getTotal();//調用後,才會執行total = 40,去改變全域變數的total值
console.log(total);//如果沒有調用function會產生「undefind」
  • 調用function改變全域變數的值。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
let a = 1;
function getTotal() {
a = 2;
console.log(a);
}
getTotal();//2
console.log(a);//2

//比較,沒有調用getTotal()
let a = 1;
function getTotal() {
a = 2
console.log(a);
}
console.log(a);//1
  • {}內找不到變數會「往外層查找」,不論是varletconst都一樣。
1
2
3
4
5
6
let a = 1;
function getTotal() {
console.log(a);
}
getTotal();
console.log(a); //1

參考資料:
MDN語法與型別
卡斯柏JavaScript 變數的宣告與他的作用域

宣告變數後賦值

透過=賦值給變數,例如let a = 1

賦值後透過console.log()才能正確地取得變數的值,如果沒賦值就會顯示undefined

函式

宣告函式(Function declaration)v.s函式表達式(Function expression)

宣告函式(Function declaration)

  • function如果不需要參數,小括號還是不能省略,function(){...}
  • return代表再調用函式後將值返回給調用此函式的代碼,如果不需要返回值,就不需要用。
  • 在宣告函式時,num1num2被稱為參數(parameter),但當調用時,在參數位置輸入的值會稱作引數,例如getTotal(3,4),裡面的3跟4就是引數(argument)。

函式表達式(Function expression)

1
2
3
4
let total = function (num1, num2) {
return num1 * num2
}
total();

方法跟宣告變數一樣,利用let宣告一個叫做total的變數,並賦予它一個匿名函式(沒有函式名稱的函式)。

兩者差異

  • 宣告函式(Function declaration)

    • 函式宣告式(function declaration)可以被提升(hoisting)到頂部,所以可以在宣告函式前,就先調用此函式。
    • typeof回傳值式"Function"
    • 函式名()調用函式。
  • 函式表達式(Function expression)

    • 不能被提升(hoisting),不能在宣告前調用此函式。
    • typeof回傳值式"Function"
    • 變數名()調用函式。

參考資料:
Fooish 程式技術的JavaScript Function (函式)
MDN語法與型別