前言
這篇文章會提到的內容如下:
- JavaScript 的變數
- 變數的類型
- 不同型態下變數運算的陷阱
- 物件的儲存方式
- JavaScript 的判斷式
JavaScript 的變數
變數 我們可以把它比喻成 箱子
,我們給這個箱子一個名稱,並放東西進去。
- 比如說我有一個叫做
文具
的箱子,我在裡面放一隻鉛筆
- 那除非我把裡面的
鉛筆
拿走或換掉,否則我所我講的文具
指的就是裡面的鉛筆。
- 那除非我把裡面的
注意:每個變數在第一次使用時都要先
宣告
,目的是告訴電腦,這個東西是什麼。宣告的方式:
var 文具 = 鉛筆
var
就是告訴電腦這是一個 變數(variable)
=
在這個地方不是我們數學上認識的 等於,它指的是把右邊的值,賦值到左邊的變數上面(也就是把鉛筆放入叫做文具的箱子裡)。
- 那如果你問我,數學的 等於 要怎麼表示?我先跟你說可以用
==
,文章後面會說明。
var 文具 = 鉛筆
console.log(文具)
結果: 鉛筆
console.log()
是叫電腦把東西印在畫面上的指令,所以在這個地方就是叫電腦把文具這個變數印在螢幕上。 最後印出的值是 鉛筆。
變數的取名
實際上我們在寫程式的時候,我們不會取中文名字,我們會用英文跟符號來表示。
變數的命名是非常重要的,要取的讓自己跟別人能看得懂。
- 你可以一看名稱就知到它代表的意思是什麼,在閱讀時才不用花太多時間
var people_count var peopleCount
- 你可以一看名稱就知到它代表的意思是什麼,在閱讀時才不用花太多時間
這兩種方式都可以看的出,這個變數想表達的是,人數 的概念。
- 上面是用
_
將兩個單字隔開 - 下面是用單字第一個字母寫成
大寫
來表示。(這種表示方式叫做 駝峰式)
- 上面是用
參考資料:
資料型態
JavaScript 有 7 種資料型態 ( 6 種原始型態 + 1 種物件型態)
Primitive type 原始型態
- null : 空值
- undefined : 有宣告變數,但是沒有值
- string : 字串
- number : 數字
- boolean : true, false
- symbol (ES6) : ES6 新增的型態,暫不討論
Object 物件型態
- object (array, function, date ......)
用
console.log(Object.prototype.toString.call(待測值))
可準確得到資料型態
補充 1: Primitive type 有不可變特性
- ex. var str = "hello"
var newStr = str.upperCase()
只能回傳新的數值,不可改變 str 的值
- ex. var str = "hello"
補充 2:null 明明是原始型態,但是用 typeof null 查看會回傳 object
- 這是 JS 廣為人知的 bug,因為一但修正了會影響太多層面,所以才決定不做修正了。
補充 3:可以用 Array.isArray() 來檢測是否是 array
陣列 & 物件
陣列
可以用來存放同類型的資料,
- 有點像是郵箱
我的 郵箱 陣列,放的都是信件,我的郵箱可以很多個,也可以 0 個。我可以任意的決定我要把信件放進哪一個郵箱,或任意的打開我想查看的郵箱。
var 郵箱 = [小明的信, 小花的信, 空的, 空的, 空的, 小白的信]
郵箱[0] = 小明的信 // 第一個郵箱裡放的是小明的信
郵箱[1] = 小花的信
郵箱[2] = 空的
郵箱[3] = 空的
郵箱[4] = 小白的信
陣列的表示方式就是用 [ ]
把東西包起來,然後把裡面的東西用 ,
號隔開。
郵箱[0]
代表我要撈取裡面第1
個資料
- 你說我寫錯了吧!第一個資料怎麼會寫 0
- 在程式語言裡,很多時候第一個資料都會是 編號 0 。
- 所以第二筆資料的編號就是 1,以此類推。
物件
用 key 跟 value 組合的一種存放資料形式。
- 組合的形式是
key: value ,
- 如果我把 key 設成 name,value 設成 長頸鹿,就可以寫成下面這樣:
var 自我介紹 = {
name : 長頸鹿 ,
age : 15 歲 ,
phone : 0800 - 092 - 000
}
這就是一個物件的寫法,用 { }
包起來,裡面寫上 key 跟 value 並且用 ,
來隔開。
我要如何取得物件的值呢? 使用 <物件名稱>.<key 的名稱>
自我介紹.name = 長頸鹿
自我介紹.age = 15 歲
自我介紹.phone = 0800 - 092 - 000
來看看實際的例子
var changekey = cat
var oProfile = {
name : "長頸鹿" ,
cat : "皇阿瑪" ,
oFather : {
name : "樹懶" ,
cat : "豆漿"
}
}
console.log( oProfile.cat ); // 皇阿瑪
console.log( oProfile["cat"] ); // 皇阿瑪
console.log( oProfile[changekey] ); // 皇阿瑪
console.log( oProfile.oFather.cat ); // 豆漿
參考資料:
你懂 JavaScript 嗎?#17 物件(Object)
變數運算的陷阱
變數運算有許多需要注意的地方
比如說
a = a + 1
是什麼意思?- 還記得上面說到的
=
是指賦值
的意思嗎? - 所以這段的意思就是把右邊的
a+1
賦值到左邊的a
var a = 0 a = a + 1 // 右邊的 a + 1 就是 0 + 1 賦值到左邊後 a 就會等於 1
- 還記得上面說到的
像這樣
自己 = 自己 ( + or - ) 數字
可以用一種縮寫方式:a = a + 5 a += 5 // 這兩行的意思是一模一樣的 a = a - 3 a -= 3 // 這兩行的意思也一模一樣
由於
+1
跟-1
這兩個動作太長需要使用了,於是就特別給他個方便的指令:++
跟--
a = a + 1 a += 1 a ++ // 這三行指令的意思是一模一樣的 a = a - 1 a -= 1 a -- // 這三行指令意思也一模一樣
需要小心的地方
若是在 =
後面直接寫上 數字,這樣變數的型態就會是 number
。
若是在 =
後面把 數字 用 "
包起來,變數型態會是 string
var a = 3 // 這邊的 a 是個 數字 number
var b = "3" // 這邊的 b 是個 字串 string
- 所以我們在運算的時候,不能夠這樣子寫
3 + "3"
,這樣會變成數字
+字串
,結果不是我們想要的。
var a = 3
var b = "3"
console.log( a + b ) // 會得到 "33"
把 數字
跟 字串
相加,程式會自動判定為 字串
相加,所以會得到 33。
- 所以我們在設定變數的時候,不能夠設定錯誤,該是
數字
就是數字
,該是字串
就是字串
,才不會發生意想不到的結果。
注意浮點數
由於 JavaScript 在儲存 小數 的時候,不會那麼精準,會帶一點誤差
(跟儲存方式有關係),所以我們在用小數做計算時,要注意這些誤差所造成的錯誤。
我們可以看到 0.1 + 0.3 是 0.4 ,但是 0.1 + 0.2 卻是 0.300000000004。
- 浮點數問題的解決方式還沒研究,先留一個參考資料:JavaScript 浮点数运算的精度问题
== v.s ===
==
:在 == 比較式中,JavaScript 會先幫兩邊不同的變數類型、先進行類型轉換、再進行比較。
3 == "3" // 會回傳 true,因為 JaveScript 會幫你先把變數類型轉換好
"1" == true // 也會回傳 true
===
:嚴格進行比較,數值與變數類型都要相同。
3 === "3" // 會回傳 false
"3" === "3" // 會回傳 true
3 === 3 // 會回傳 true
- 為了避免變數類型的疑慮,在寫程式時,建議使用嚴謹一點的
===
判斷相等。
從物件了解變數
記憶體位置:
假設有兩個物件 obj1, obj2 我們放入一樣的東西之後做比較:
var obj1 = { a : 1 };
var obj2 = { a : 1 };
console.log( obj1 === obj2 ) // 會回傳 false
- 兩個物件放入一模一樣的東西,相比結果卻是 false。
這個不是 bug 讓我們慢慢解釋
- 因為 JavaScript 在
物件
的比較,是比較記憶體位置
。- 第一個 obj1 會在電腦裡
新增
一個記憶體位置,假設是 01x01,裡面存放著 {a: 1} - 第二個 obj2 會在電腦裡
再新增
一個新的記憶體位置,假設是 01x05,裡面存放著 {a: 1} - 而 obj === obj2 比較的其實是 0x01 === 0x05,所以當然會回傳 false 啦!
- 第一個 obj1 會在電腦裡
兩個物件 obj1, obj2 但這次我們把第二個物件 obj2 指向第一個:
var obj1 = { a : 1 };
var obj2 = obj1
接著在更改 obj2 的值,看看會發生什麼事
obj2.a = 2;
console.log( obj1 ) // 結果是 2
console.log( obj1 === obj2 ) // 結果是 true ,相同記憶體位置
- 當我們把 obj2 指向 obj1 的時候,會把 obj2 指向跟 obj1 一樣的記憶體位置。
- 因為兩個物件是指向同個記憶體位置,所以改動其中一個物件的值,另一個物件的內容也會改變。
但若是我將 obj2 指向 obj1 後,又 賦值
一個新的內容進去
var obj1 = { a: 1 };
var obj2 = obj1;
console.log( obj2 === obj1 ) // true 此時指向同個記憶體位置
obj2 = { b: 1 ); // 賦值新的內容進去
console.log( obj2 === obj1 ) // false 此時指向的記憶體位置就不同了
- 當 obj2 被傳入新的內容,就會給 obj2 一個新的記憶體位置,所以兩個物件的連結就斷開了。
JavaScript 的判斷式
如果今晚有空,我們一起去看電影,沒空的話就下次再約
- 這就是很標準的判斷式,判斷條件成立的話要做什麼,條件不成立要做什麼
- 換成 JavaScript 語法:
if ( 今晚有空 ) { 一起看電影 } else { 下次再約 }
if
中括號( )
裡面的條件成立,就執行大括號{ }
裡面的動作,否則就執行else
後面的動作。
條件不只有兩個怎麼辦?
若是條件不只兩個,可以用下面的方式:
var age = 年齡 if ( age === 18 ) { // 如果滿足 age === 18 console.log("你剛成年唷!") } else if ( age <= 18 ) { // 若上面條件不滿足,再判斷是否滿足 age <= 18 console.log("你未成年喔!") } else { // 若上面條件通通不滿足 console.log("你成年了!") }
第二種條件表示方式:switch (這個條件判斷其實不常用)
如果太多太多選擇了,可以利用 switch
var month = 1
switch ( month ) {
case 1 : // 若滿足 month === 1
console.log("一月")
break
case 2 : // 若滿足 month === 2
console.log("二月")
break
case 3 : // 若滿足 month === 3
console.log("三月")
break
.
.
.
default : // 若上面條件通通都不滿足
console.log("輸入的月份有誤")
}
在 switch
的條件下,就算第一個 case
已經滿足了,程式還是會一直執行下去,所以每一個條件最後都要加一個 break
,告訴電腦我要跳出條件判斷。
第三種條件表示方式:三元運算子
語法:
condition? A : B
- 判斷 condition 如果為 true 就回傳 A
- 判斷 condition 如果為 false 就回傳 B
舉一個成績判斷為例子:
var score = 70;
var result;
if ( score >= 60 ) {
result = pass
} else {
result = fail
}
- 換成以 三元運算子 來表示:
var score = 70
var result = score >= 60 ? pass : fail
後言
因為三元運算子的程式碼非常簡潔,一開始學習三元運算子真的覺得超級不直觀,想半天都搞不懂這行程式碼是什麼鬼。一開始練習題目還是會以 if
, else
為主,但有空還是要強迫自己熟悉三元運算子的寫法,看那些厲害的高手寫程式都是用簡潔的方式寫。