迴圈 loop
do while
先執行一次 do
裡面的動作,接著判斷是否符合 while
的條件,符合就再執行一次,直到不符合條件為止。
var i = 1
do {
console.log(i)
i++
} while (i <= 100)
- 一開始宣告一個變數 i = 1
- 執行
do
裡面的動作: console.log 印出 i 之後,再把 i + 1 - 判斷是否符合
while
條件,因為現在的 i = 2 有符合條件,所以再做一次do
裡面的事情 - 直到 i > 100 不符合條件,就會跳出迴圈
while 迴圈
當 whilt
的條件滿足時,執行 { }
裡面的動作。
var i = 1
while (i <= 100) {
console.log(i)
i++
}
- 一開始宣告一個變數 i = 1
- 判斷是否符合
while
的條件,i = 1 有符合條件 - 執行
{ }
裡面的動作:console.log 印出 i 之後,再把 i + 1 - 再判斷一次是否符合
while
的條件,i = 2 有符合條件 - 再繼續執行
{ }
裡面的動作 - 直到不符合條件為止
- 補充:
continue
可以跳過這圈未完成的動作,直接進到下一圈迴圈break
可以強制跳出迴圈
for loop 迴圈
用法: for ( 起始條件; 終止條件; 每一圈的改變 ) { 每一圈要做的事情 }
- 範例:
for ( var i=1; i<=100; i++) {
console.log(i)
}
- 起始條件是 i = 1,終止條件是 i <= 100,每一圈的改變是 i = i+1
- 符合條件就會執行
{ }
裡面的事情。
- 假設我有一個存放成績的陣列
scores
,我想要用for loop
來把成績加總,我們可以這樣寫:
var scores = [ 80, 75, 73, 89, 91 ]
var scores_sum = 0
for ( var i=0; i<scores.length; i++) {
scores_sum += score[i]
}
console.log( scores_sum )
函式 function
函式的基本結構
function <函式名> ( 參數 ) {
函式內容
return 我要回傳的東西
}
- 我們會設定需要傳什麼參數進去,並在
{ }
中寫下函式的內容 - 以把三個數字相加為例:
function add ( a, b, c ) {
return a + b + c
}
- 我寫了一個叫做 add 的函式,並傳入 a, b, c 三個參數
- 這個函式會回傳 a + b + c 的結果
宣告函式的不同種方式
function hello () {
console.log( "hello" )
}
var hello = function() {
console.log( "hello" )
}
上面兩種方式,表示都是叫做 hello 的函式
- Function 參數也可以丟入 Function
var scores = [ 80, 75, 81, 92 ]
function scores_sum ( scores, add ) {
var sum = 0
for ( var i=0; i<scores.length; i++) {
add ( sum, scores )
}
return sum
}
console.log(
scores_sum( scores, function( num1 , num2 ) {
return num1 += num2
})
)
引數(Argument)與參數(Parameter)
參數
是函式所接收的數值
引數
是實際傳入函式的數值 (實際引用進來的)
以下面函式為例:
function fun1 ( a, b ) { return a + b } var c = 1 var d = 2 console.log( fun1 ( c, d ))
我們可以看到 fun1 接收 a,b 所以 a,b 就是
參數
- 實際我們呼叫 fun1 時所傳入的值是 c,d,所以 c,d 是
引數
JavaScript 有提供一個功能,可以讓我們在函式中查看傳進來的引數是什麼
function fun1 () {
console.log (arguments)
}
- 像這樣 console.log 或者是 return arguments,就可以查看引數的東西。
- 補充: arguments 是一個物件不是陣列,所以引用的時後要注意一下。
使用 function 要注意的事項
Pass by value
- 引數傳入 function 之後,有點像是把數值複製一份帶入 function 裡面
function addValue (a, b) {
return a + b
}
var c = 1
var d = 2
addValue ( c , d )
像這個例子,引數傳入函式 addValue 的時候,概念上會像這樣:
a = c // 先把 c 的值複製一份給 a
b = d // 也把 d 的值複製一份給 b
- 從 code 來看:
function swap ( a, b ) { // 一個會把 a, b 值互換的函式
var temp = a
a = b
b = temp
}
var num1 = 10
var num2 = 5
swap ( num1, num2 ) // 函式會把帶入的 10, 5 互換
console.log( num1, num2 ) // num1 = 10 num2 = 5
- 把 num1, num2 帶入 swap
- a = num1 = 10 , b = num2 = 5 把引數的值複製一份給參數
- 把 a, b 值互換,所以 a 變成 5,b 變成 10
- 回頭看 num1 跟 num2 的值依然沒有改變,num1 = 10, num2 = 5
原始型別 num、string、boolean 都是傳值 pass by value,原來的 num1、num2 並沒有被更改。
pass by reference
- 「你傳進去的東西就是真的 num1 跟 num2,function 裡面的 a 跟 b 只是別名(alias)而已,改變 a 就會改變 num1」
- 不適用於 原始型別 num、string、boolean
- 我們要用 object 來舉例:
function add(obj){
obj.number++
}
var o = {
number: 10
}
add(o)
console.log( o.number ) // 11
因為 物件型態
備份的值會是 記憶體位置
,所以備份引數的記憶體位置後,物件 o 與物件 obj 會指向同一個記憶體位置,改變函式中物件 obj 的內容,也會改動到函式外的物件 o 的內容。
但是有一個重點!
- 上面用了
object
來舉出 pass by reference 的特性,但是實際上 object 在 JavaScript 並不是用 pass by referencr。
pass by sharing
function add(obj) {
讓 obj 變成一個新的 object
obj = {
number: obj.number + 1
}
}
var o = {
number: 10
}
add(o)
console.log( o.number ) // 10
- pass by sharing 跟 pass by reference 的特性一樣,可以讓函式內與函式外「共享」同一份資料,所以透過裡面的 obj,你可以去修改「共享到的那個 object」的資料。
- 差別在於如果在 function 裡面把 obj 重新賦值,就代表你要讓這個 obj 指向一個新的 object,所以外面的 o 依舊還是原來的值。(指向的記憶體位置就不同了)
JavaScript 的 primitive type 是 pass by value,object 是 pass by sharing
回傳 & 印出
return
用來將函式的結果回傳出去。
- 你可以設定不同情況下回傳不同的結果
- 一但執行 return,會直接跳出函式。
- 不寫 return 也可以,但是 console.log 要印出這個函式的結果時會印出一個 undefine,表示你沒有回傳值。
function fun1(age) {
if(age >= 18) return bigger
if(age < 18) return smaller
}
var age = 20
if( fun1(age) === bigger ) console.log( "成年了" )
if( fun1(age) === smaller ) console.log( "未成年" )
- age >= 18 或者 age < 18 兩種不同情況 return 不同的結果
- 在滿足 age >= 18 的情況下 return bigger 後,下面的程式就不執行了
return 跟 console.log 的差異是什麼
- 當這個函需要輸出你想要的結果時,它一定需要有 return,這樣別人來呼叫這個函式的時候,才能拿到他輸出的結果
function fun1( a, b ) {
var answer = a + b
return answer
}
var result = fun1 ( 10, 5 )
//result 的值會等於 fun1 回傳的結果
- 如果要將某一筆資料印出來查看,可以用 console.log
function fun1( a, b ) {
var answer = a + b
console.log( a, b )
return answer
}
fun1 ( 10, 5 )
- 這個函式會先印出 a, b 是什麼
- 在回傳 a + b 的答案
- 回傳的值,如果沒有另外用 console.log 來顯示,它就不會印出來給你看。
常用內建函式
內建函式是程式語言提供給你,讓你直接可以使用的函式。
數學相關函式
Math.ceil()
: 無條件進位Math.floor()
: 無條件捨去Math.round()
: 四捨五入Math.random
: 產生 0 ~ 1 的隨機數( 不包括 1 )Math.max(num1, num2, num3)
: 丟入一系列數字,回傳最大值
也可以丟陣列,但寫法要用 展開運算子 ...,例如: Max.max(...arr)Math.min(num1, num2, num3)
: 丟入一系列數字,回傳最小值- 用法如同 Math.max()
Number.MAX_VALUE
: 回傳 JavaScript 能存的最大數字。Number.toFixed(x)
: 取到小數點後第 x 位數( 無條件捨去 )Math.sqrt()
: 開根號Math.log()
: 對數Math.pow(x, y)
: 次方運算- x 的 y 次方
字串、數字間互相轉換
- 字串轉數字:
parseInt(<strin>, x)
x 代表你要轉換成幾進位表示Number(<string>)
console.log( parseInt( "20" , 10 ) // 20
console.log( parseInt( "101001", 2 ) // 41
console.log( Number( "20" ) //20
- 把 "20" 轉換成 10進位 表示的數字 , 也就是 20
- 把 "101001" 轉換成 2進位 表示的數字 , 也就是 41
- 把 "20" 轉換成數字,也就是 50
- 數字轉字串
<number>.toString()
<number + ''
var num = 20
console.log( num.toString() ) // "20"
console.log( num + '' ) // "20"
將數字跟字串相加,系統會自動判別為字串相加,所以可以利用加上空字串 ''
來把數字轉換為字串。
字串相關函式
length
: 回傳字串的長度toUpperCase()
: 將字串全部轉為大寫toLowerCase()
: 將字串全部轉為小寫charCodeAt(char)
: 取出字元的 ASCII 碼String.fromCharCode(num)
: 將 ASCII 碼轉成字元indexOf(keyword)
: 找出關鍵字 keyword 有沒有在字串裡- 有,回傳 keyword 索引值
- 沒有,回傳 -1
replace(x, y)
: 找的第一個 x 字串,用 y 取代- 如果要取代所有的 x,要用正規表達式 : replace(/x/g ,y)
split(x)
: 分割字串成陣列- 用 x 作為分割字串的參考,回傳陣列
trim()
: 去掉前後的空格
字串、陣列間互相轉換
- 字串轉陣列
str.split('')
以空格為切割標的- 可自訂要以什麼方式切開,例如
,
或-
- 陣列轉字串
arr.join('')
直接合成一個字串,不隔開- 可以自訂以什麼方式隔開,例如
,
var str = "apple, banana"
console.log( str.split(',')) // [ 'apple', ' banana' ]
var arr = [ "apple", "banana" ]
console.log( arr.join(',')) // apple,banana
常用的陣列相關函式 (這部分找時間獨立出來整理)
join()
: 把所有元素轉成字串,串接回傳結果字串(預設用逗號分割)。reverse()
:倒轉陣列元素的順序,並回傳結果sort()
:將元素排序concat()
:如果引數值有陣列,會把引數值加入並回傳一個新陣列slice()
:回傳擷取出的元素splice()
:用新的元素取代掉原本的元素push()
與pop()
- push() 是將新的元素推進陣列的最後
- pop() 是將陣列最後一個元素回傳並把它移除掉
unshift()
與shift()
- unshift() 是將新的元素推到陣列的開頭
- shift() 是回傳陣列的第一個值並把它移除掉
toString()
:把陣列元素轉成字串,用逗號分隔輸出一字串
immutable 觀念
- immutable 不可變:除了
物件型態
以外的變數基本上都不可變
var a = "Hello" // 在 0x01 存放一個值為 Hello
a = "Yo" // 在 0x02 存放一個值為 Yo
a = a + "Yo" // 在 0x03 存放一個新的 HelloYo
- 當我們重新賦值的時候,不會改動原本記憶體下的值,而是新建一個記憶體空間。
用一個變數去呼叫 function
var a = "hello"
a.toUpperCase()
console.log(a) // hello
- a 是原始型態,用 a 去呼叫函式不會改變原本 a 的值
var a = "hello"
a = a.toUpperCase
console.log(a) // HELLO
- 用 a 去呼叫函式,並
賦值
回原本的 a,程式會回傳給 a 新的值並存在新的記憶體位置。
var a = "hello"
var temp = a.toUpperCase()
console.log(temp) // HELLO
- 或者是另外宣告一個新的變數,去接收回傳出來的值
物件型態,可以直接於同一個記憶體改變內容
var arr = [ 1, 2, 3 ] // 0x01
arr.push(4)
console.log(arr) // [1,2,3,4] 0x01
- 用 arr 呼叫 push 這個函式,會直接在相同的記憶體底下更改 arr 的內容,不會新增一個新的記憶體位置
- 除非,函式回傳的值已經不是一個陣列了
對於 字串
或 數字
來說,永遠不會這樣子寫:
var str = "hello"
str.toUpperCase()
這樣子寫是沒有用的
對於 物件
或 陣列
來說,通常也不會這樣子寫:
var arr = [ 1,2,3 ]
arr = arr.slice(2)
這樣回傳回來的值就不是 array 了
- 關鍵就是要判斷,這個函式是會回傳還是改動原本的值,或者既回傳又改變原本的值。