物件簡單來說,就是把一堆有關係的資料全部群組在一起,所組成的集合資料。
特點:
屬性名:值
。物件成員 | 可代入的值 | 值的型別 |
---|---|---|
屬性 | 原生值 (包含鍵值對) | boolean 、number 、string ...等 |
屬性 | 物件 (包含鍵值對) | object |
方法 | 函數 | function |
聽起來好抽象,拿車子來當例子吧!
等等,放錯了...下面這個才對!!
由上表,可以清楚看出,車子本身相當於「物件」,而車型是跑車、顏色是紅色、重量1500kg、馬力2000匹等條件就是車子的「屬性」,其中車型就是「屬性名」,跑車就是「值」,車型:跑車就是「鍵值對」。而如何啟動、加速、剎車等行為或可作的動作。就是車子的「方法」。
簡單來說,所有的車子通通都具有相同的屬性或方法,只是屬性中的值會因車子不同而有所不同,且方法也會在不同時間執行。
來個簡單的例子好了!我家成員有爸爸、媽媽、2 個女兒,爸爸名字叫 John
、媽媽叫 Mary
、女兒分別叫 Nancy
和 Juno
。該怎麼把它寫成 JavaScript 呢?
1、先建立空物件。
const
或 let
關鍵字來「宣告物件」,首先宣告我家 myFamily
這個變數。{ }
把物件成員寫在裡面,注意在右邊的大括號後方需加上分號 ;
來結束該語句。const myFamily = {};
2、定義物件成員的鍵值對。
屬性名: 值
,如 father: 'John'
。father
、媽媽 mother
、兩個女兒 daughter1
、daughter2
,值就是家庭成員各自的名字(字串)。,
分隔,然後斷行便於區分。father: 'John',
mother: 'Mary',
daughter1: 'Nancy',
daughter2: 'Juno'
3、我們可以看到光女兒就佔了兩行,好像有點重複,不知道是否可以寫簡單點。
其實有的,下個章節會介紹到的「陣列 Array
」就是運用在這,因為陣列特色是可以集合許多事物的相同資訊。
陣列寫法非常簡單,用中括號 [ ]
包覆有相同屬性名的值,每個值再用逗號 ,
分開,最後一個不需要加逗號。(疑?看起來和定義物件的寫法有點相似!)
像剛剛的女兒1號、2號,其實都是「女兒」的意思(相同屬性名),我們就把屬性名改為女兒們 daughters
便可共用,再把她們的名字通通用陣列放在一起!
daughters: ['Nancy','Juno']
4、和上面第一項的空物件整合之後就變這樣:
const myFamily = {
father: 'John',
mother: 'Mary',
daughters: ['Nancy','Juno'],
};
圖解:
物件型別 object
還有幾個子型別:
function
(函數)array
(陣列)date
(日期)regExp
(正規表達式)全部的型別都介紹完畢了,我們可以使用 typeof
指令來檢測值的型別是什麼。
console.log(typeof 'Nancy'); // 回傳 string(字串)
console.log(typeof 593.17); // 回傳 number(數字)
console.log(typeof false); // 回傳 boolean(布林)
console.log(typeof symbol); // 回傳 symbol(符號)
console.log(typeof [1,2,3,4]); // 回傳 object(物件)
console.log(typeof {name:'Nancy', age:18}); // 回傳 object(物件)
console.log(typeof function(){}); // 回傳 function(函數)
console.log(typeof null); // 回傳 object(物件)
console.log(typeof undefined); // 回傳 undefined(未定義)
不過從上面的程式碼可以看到其中有幾項怪怪的...
console.log(typeof function(){}); // 回傳 function (函數)
我們從 object
物件型別了解到 function
函數是它的子型別,但是根據 MDN 官方文件說明, typeof function(){}
的回傳值會得到 function
而不是 object
,雖然如此,它仍屬於物件的一種。
因為函數是一種「可呼叫的物件 Callable Object」,也被稱為「函數物件 Function Object」。函數擁有 [[Call]]
的內部特性,讓它成為能夠被調用的物件。所以如果用 function
當作建構子所建立出來的物件,再用 typeof
檢測值就會回傳是 object
了,就是因為「函數同時也是物件」這樣的特性。
console.log(typeof null); // 回傳 object (物件)
咦? null
不是應該是基本型別之一嗎,怎麼會是複合型別 object
。
結果根據 W3C 的說明,它是一個歷史遺留的 Bug!本來在 ES6 中,曾有機會為歷史平凡,將 typeof null
的值翻轉為 null
,但最後被拒絕了。原因是歷史遺留程式碼太多了,為了不得罪任何人,不如繼續將錯就錯吧...
有興趣的可以去查一下。
參考資料:
上一篇:【JS幼幼班】Step.06 基本語法:基本型別(string、symbol)
下一篇:【JS幼幼班】Step.08 基本語法:物件型別(Array、date)
物件簡單來說,就是把一堆有關係的資料全部群組在一起,所組成的集合資料。
特點:
屬性名:值
。物件成員 | 可代入的值 | 值的型別 |
---|---|---|
屬性 | 原生值 (包含鍵值對) | boolean 、number 、string ...等 |
屬性 | 物件 (包含鍵值對) | object |
方法 | 函數 | function |
聽起來好抽象,拿車子來當例子吧!
等等,放錯了...下面這個才對!!
由上表,可以清楚看出,車子本身相當於「物件」,而車型是跑車、顏色是紅色、重量1500kg、馬力2000匹等條件就是車子的「屬性」,其中車型就是「屬性名」,跑車就是「值」,車型:跑車就是「鍵值對」。而如何啟動、加速、剎車等行為或可作的動作。就是車子的「方法」。
簡單來說,所有的車子通通都具有相同的屬性或方法,只是屬性中的值會因車子不同而有所不同,且方法也會在不同時間執行。
來個簡單的例子好了!我家成員有爸爸、媽媽、2 個女兒,爸爸名字叫 John
、媽媽叫 Mary
、女兒分別叫 Nancy
和 Juno
。該怎麼把它寫成 JavaScript 呢?
1、先建立空物件。
const
或 let
關鍵字來「宣告物件」,首先宣告我家 myFamily
這個變數。{ }
把物件成員寫在裡面,注意在右邊的大括號後方需加上分號 ;
來結束該語句。const myFamily = {};
2、定義物件成員的鍵值對。
屬性名: 值
,如 father: 'John'
。father
、媽媽 mother
、兩個女兒 daughter1
、daughter2
,值就是家庭成員各自的名字(字串)。,
分隔,然後斷行便於區分。father: 'John',
mother: 'Mary',
daughter1: 'Nancy',
daughter2: 'Juno'
3、我們可以看到光女兒就佔了兩行,好像有點重複,不知道是否可以寫簡單點。
其實有的,下個章節會介紹到的「陣列 Array
」就是運用在這,因為陣列特色是可以集合許多事物的相同資訊。
陣列寫法非常簡單,用中括號 [ ]
包覆有相同屬性名的值,每個值再用逗號 ,
分開,最後一個不需要加逗號。(疑?看起來和定義物件的寫法有點相似!)
像剛剛的女兒1號、2號,其實都是「女兒」的意思(相同屬性名),我們就把屬性名改為女兒們 daughters
便可共用,再把她們的名字通通用陣列放在一起!
daughters: ['Nancy','Juno']
4、和上面第一項的空物件整合之後就變這樣:
const myFamily = {
father: 'John',
mother: 'Mary',
daughters: ['Nancy','Juno'],
};
圖解:
物件型別 object
還有幾個子型別:
function
(函數)array
(陣列)date
(日期)regExp
(正規表達式)全部的型別都介紹完畢了,我們可以使用 typeof
指令來檢測值的型別是什麼。
console.log(typeof 'Nancy'); // 回傳 string(字串)
console.log(typeof 593.17); // 回傳 number(數字)
console.log(typeof false); // 回傳 boolean(布林)
console.log(typeof symbol); // 回傳 symbol(符號)
console.log(typeof [1,2,3,4]); // 回傳 object(物件)
console.log(typeof {name:'Nancy', age:18}); // 回傳 object(物件)
console.log(typeof function(){}); // 回傳 function(函數)
console.log(typeof null); // 回傳 object(物件)
console.log(typeof undefined); // 回傳 undefined(未定義)
不過從上面的程式碼可以看到其中有幾項怪怪的...
console.log(typeof function(){}); // 回傳 function (函數)
我們從 object
物件型別了解到 function
函數是它的子型別,但是根據 MDN 官方文件說明, typeof function(){}
的回傳值會得到 function
而不是 object
,雖然如此,它仍屬於物件的一種。
因為函數是一種「可呼叫的物件 Callable Object」,也被稱為「函數物件 Function Object」。函數擁有 [[Call]]
的內部特性,讓它成為能夠被調用的物件。所以如果用 function
當作建構子所建立出來的物件,再用 typeof
檢測值就會回傳是 object
了,就是因為「函數同時也是物件」這樣的特性。
console.log(typeof null); // 回傳 object (物件)
咦? null
不是應該是基本型別之一嗎,怎麼會是複合型別 object
。
結果根據 W3C 的說明,它是一個歷史遺留的 Bug!本來在 ES6 中,曾有機會為歷史平凡,將 typeof null
的值翻轉為 null
,但最後被拒絕了。原因是歷史遺留程式碼太多了,為了不得罪任何人,不如繼續將錯就錯吧...
有興趣的可以去查一下。
參考資料:
上一篇:【JS幼幼班】Step.06 基本語法:基本型別(string、symbol)
下一篇:【JS幼幼班】Step.08 基本語法:物件型別(Array、date)
字串是用 2 個引號(單引號或雙引號都可以)包住的文字。
而引號內的文字內容和字數不限,甚至可以使用空格或任何符號。
//正確寫法
let str1 = 'I have 3 dogs, and my sister have 2 cats.';
let str2 = "中文 にほんご español English हिन्दी العربية português বাংলা ਪੰਜਾਬੀ 한국어";
let str3 = '12.345+-*/%~~';
如果字串裡面也要包含引號呢?必須要用不同引號互包。
//正確寫法
let str4 = "Don't worry be happy.";
console.log(str4); // 回傳 Don't worry be happy.
let str5 = '我的名字是"難吸",請多指教!';
console.log(str5); // 回傳 我的名字是"難吸",請多指教!
都是相同引號互包,就會出錯。
//錯誤寫法
let str6 = 'Don't worry be happy.';
console.log(str6); // 回傳 錯誤 Uncaught SyntaxError: Unexpected identifier
let str7 = "我的名字是"難吸",請多指教!";
console.log(str7); // 回傳 錯誤 Uncaught SyntaxError: Unexpected identifier
如果一定要相同的引號互包呢?或是要使用多行字串呢?
就在內包的引號左邊加上反斜線 \
,而且 \
的後方不可出現任何東西(包含空格),以及內包的引號只能使用單數個。
//正確寫法
let str8 = 'Don\'t worry be happy.';
console.log(str8); // 回傳 Don't worry be happy.
let str9 = "我的名字是\"難吸,請多指教!";
console.log(str9); // 回傳 Don't worry be happy.
如果內包的引號出現雙數個,就會出錯。
//錯誤寫法
let str10 = "我的名字是\"難吸",請多指教!";
console.log(str10); // 回傳 錯誤 Uncaught SyntaxError: Unexpected identifier
多行字串也是使用反斜線 \
寫法:
let txt = '這是第一行 \
這是第二行 \
這是第三行';
若遇到單行內有多組的字串相連,或字串和非字串相連,則用加號 +
來連接:
let sayHello = '嗨!我叫難吸。' + '你呢?';
console.log(sayHello); // 回傳 嗨!我叫難吸。你呢?
let myPets = 'I have ' + 2 + ' dogs.';
console.log(myPets); // 回傳 I have 2 dogs.
symbol
符號為 ES6 新增的基本資料型別,它是用來表示獨一無二的屬性名。語法如下:
Symbol([description])
它最大的用法是用來定義 object
物件的「唯一」屬性名,以防止不會跟其他的屬性名產生衝突,括號內的 description
為可選參數或字串。
p.s:「物件 object
」因尚未介紹,可先連結到下一篇了解一下什麼是物件 object
。這裡「物件 object
」解釋為多種屬性資料的集合列表。
看不太懂?那我們解釋白話點吧。
在ES6之前,object
物件的屬性名只能是字串,若不是字串則會被強制轉為字串。如果要幫一個物件添加新的屬性名,很容易會造成名稱衝突。例如:我想列表出朋友的一些資料,於是取了一個物件叫 myFriends
,資料有年齡 age
、關係 relationship
、性別 sex
:
let myFriends = {
'小美' : {
age: 35,
relationship: 'my boy friend',
sex: 'Male'
},
'小美' : {
age: 28,
relationship: 'friend',
sex: 'Female'
},
'跳跳' : {
age: 6,
relationship: 'my dog',
sex: 'Female'
},
};
上面的寫法好陌生...沒關係!這裡只是介紹各個型別的作用,未來的篇幅會更詳細說明寫法,我們先了解就好,趕快回到主題。
咦?上方的程式裡,剛好有兩位朋友都叫小美,撞名了怎辦!
之前在第二篇的時候有教過使用 console.log()
指令寫入瀏覽器控制台,來檢查自己寫的程式碼有沒有問題。我們來測試看看結果吧!
console.log(myFriends);
可以發現小美的資料只剩下一位,而且是下面的那位,第一位小美不見了。代表屬性名相同的,後者會蓋掉前者的資料。這下可GG了,第一位怎麼讓它出現呢?兩個小美我都想要看到阿!
這時候 symbol
符號就是我們的救星了。由於每個 symbol
的值都是獨一無二、不相等的,所以用它來當作物件的屬性名稱,可以確保不會出現同名的屬性,而這個特性才能防止物件的屬性不會在其他地方被意外的覆蓋掉。
話不多說,趕快用 symbol
來拯救小美 1 號吧!順便 console.log
結果。
let myFriends = {
[Symbol('小美')] : {
age: 35,
relationship: 'my boy friend',
sex: 'Male'
},
[Symbol('小美')] : {
age: 28,
relationship: 'friend',
sex: 'Female'
},
[Symbol('跳跳')] : {
age: 6,
relationship: 'my dog',
sex: 'Female'
},
};
console.log(myFriends);
這時候就可以看到兩位小美都完整的出現在名單裡面了,而且一個也不缺。
當然 symbol
符號還有許多不同的用法,在這就不贅述,有興趣的可以到官方 MDS 網站或下方的參考資料研究一下。
參考資料:
上一篇:【JS幼幼班】Step.05 基本語法:基本型別(空值、boolean、number)
下一篇:【JS幼幼班】Step.07 基本語法:物件型別(object、function)
字串是用 2 個引號(單引號或雙引號都可以)包住的文字。
而引號內的文字內容和字數不限,甚至可以使用空格或任何符號。
//正確寫法
let str1 = 'I have 3 dogs, and my sister have 2 cats.';
let str2 = "中文 にほんご español English हिन्दी العربية português বাংলা ਪੰਜਾਬੀ 한국어";
let str3 = '12.345+-*/%~~';
如果字串裡面也要包含引號呢?必須要用不同引號互包。
//正確寫法
let str4 = "Don't worry be happy.";
console.log(str4); // 回傳 Don't worry be happy.
let str5 = '我的名字是"難吸",請多指教!';
console.log(str5); // 回傳 我的名字是"難吸",請多指教!
都是相同引號互包,就會出錯。
//錯誤寫法
let str6 = 'Don't worry be happy.';
console.log(str6); // 回傳 錯誤 Uncaught SyntaxError: Unexpected identifier
let str7 = "我的名字是"難吸",請多指教!";
console.log(str7); // 回傳 錯誤 Uncaught SyntaxError: Unexpected identifier
如果一定要相同的引號互包呢?或是要使用多行字串呢?
就在內包的引號左邊加上反斜線 \
,而且 \
的後方不可出現任何東西(包含空格),以及內包的引號只能使用單數個。
//正確寫法
let str8 = 'Don\'t worry be happy.';
console.log(str8); // 回傳 Don't worry be happy.
let str9 = "我的名字是\"難吸,請多指教!";
console.log(str9); // 回傳 Don't worry be happy.
如果內包的引號出現雙數個,就會出錯。
//錯誤寫法
let str10 = "我的名字是\"難吸",請多指教!";
console.log(str10); // 回傳 錯誤 Uncaught SyntaxError: Unexpected identifier
多行字串也是使用反斜線 \
寫法:
let txt = '這是第一行 \
這是第二行 \
這是第三行';
若遇到單行內有多組的字串相連,或字串和非字串相連,則用加號 +
來連接:
let sayHello = '嗨!我叫難吸。' + '你呢?';
console.log(sayHello); // 回傳 嗨!我叫難吸。你呢?
let myPets = 'I have ' + 2 + ' dogs.';
console.log(myPets); // 回傳 I have 2 dogs.
symbol
符號為 ES6 新增的基本資料型別,它是用來表示獨一無二的屬性名。語法如下:
Symbol([description])
它最大的用法是用來定義 object
物件的「唯一」屬性名,以防止不會跟其他的屬性名產生衝突,括號內的 description
為可選參數或字串。
p.s:「物件 object
」因尚未介紹,可先連結到下一篇了解一下什麼是物件 object
。這裡「物件 object
」解釋為多種屬性資料的集合列表。
看不太懂?那我們解釋白話點吧。
在ES6之前,object
物件的屬性名只能是字串,若不是字串則會被強制轉為字串。如果要幫一個物件添加新的屬性名,很容易會造成名稱衝突。例如:我想列表出朋友的一些資料,於是取了一個物件叫 myFriends
,資料有年齡 age
、關係 relationship
、性別 sex
:
let myFriends = {
'小美' : {
age: 35,
relationship: 'my boy friend',
sex: 'Male'
},
'小美' : {
age: 28,
relationship: 'friend',
sex: 'Female'
},
'跳跳' : {
age: 6,
relationship: 'my dog',
sex: 'Female'
},
};
上面的寫法好陌生...沒關係!這裡只是介紹各個型別的作用,未來的篇幅會更詳細說明寫法,我們先了解就好,趕快回到主題。
咦?上方的程式裡,剛好有兩位朋友都叫小美,撞名了怎辦!
之前在第二篇的時候有教過使用 console.log()
指令寫入瀏覽器控制台,來檢查自己寫的程式碼有沒有問題。我們來測試看看結果吧!
console.log(myFriends);
可以發現小美的資料只剩下一位,而且是下面的那位,第一位小美不見了。代表屬性名相同的,後者會蓋掉前者的資料。這下可GG了,第一位怎麼讓它出現呢?兩個小美我都想要看到阿!
這時候 symbol
符號就是我們的救星了。由於每個 symbol
的值都是獨一無二、不相等的,所以用它來當作物件的屬性名稱,可以確保不會出現同名的屬性,而這個特性才能防止物件的屬性不會在其他地方被意外的覆蓋掉。
話不多說,趕快用 symbol
來拯救小美 1 號吧!順便 console.log
結果。
let myFriends = {
[Symbol('小美')] : {
age: 35,
relationship: 'my boy friend',
sex: 'Male'
},
[Symbol('小美')] : {
age: 28,
relationship: 'friend',
sex: 'Female'
},
[Symbol('跳跳')] : {
age: 6,
relationship: 'my dog',
sex: 'Female'
},
};
console.log(myFriends);
這時候就可以看到兩位小美都完整的出現在名單裡面了,而且一個也不缺。
當然 symbol
符號還有許多不同的用法,在這就不贅述,有興趣的可以到官方 MDS 網站或下方的參考資料研究一下。
參考資料:
上一篇:【JS幼幼班】Step.05 基本語法:基本型別(空值、boolean、number)
下一篇:【JS幼幼班】Step.07 基本語法:物件型別(object、function)
所有的程式語言都具有「資料型別」和「資料結構」的設計。
在 JavaScript 中,分為兩大類資料型別。
「基本型別 Primitive Type」:
null
(空值)undefined
(未定義值)boolean
(布林)number
(數字)string
(字串)symbol
(符號) - ES6 新增「物件型別 Object Type」:
object
(物件):function
(函數)array
(陣列)date
(日期)regExp
(正規表達式)知道資料的型別,才能知道值屬於什麼類型,可以支援哪些操作。
簡單舉例:
a = 1 + 1
如果沒有給予值 1
型別的話,電腦就會無法辨識 a
的結果到底是要用數字相加( 1 + 1 等於 2 ),還是字串相加(文字 1 + 文字 1 等於文字 11 )。
空值分為兩種,兩者都是特殊關鍵字keyword,但表示的意義不同:
null
:表示變數「有定義」值,只是該值為空的,表示沒有結果的操作。undefined
:表示變數「沒有定義」值或「未指定」值,所以你無法使用。一般來說,明確使用 null
表示空值比較好,因為若使用 undefined
表示空值,會被誤以為是忘了定義值。
曾經看過一個有趣的形容,可能讓新手們更容易了解其中的意義:
空字串 : 裝水的杯子今天沒裝水。
null : 沒有杯子。
undefined : 連是不是杯子都不知道。
布林只有兩個值,表示邏輯上的「真」或「假」,在真假判斷式中,所有東西都可以轉換為布林值:
布林值 | 邏輯判斷 | 特殊值判定 |
---|---|---|
true |
真 | {} 、[] 、" " |
false |
假 | 0 、NaN 、'' 、null 、undefined |
不過我們很少直接寫出 true
或 false
,而是會撰寫條件式來改變程式執行流程。
轉型 falsy、truthy
Boolean(value)
去把值轉型為布林值。false
的,稱為 「falsy
」值,而變成 true
的,則叫 「truthy
」值。只有以下這 8 個特殊值透過轉型就會變成 false
,除此之外都是 true
:
false
0
-0
NaN
''
(單引號空字串)""
(雙引號空字串)null
undefined
另外還有幾個特殊值要注意,它是屬於 true
:
{}
(空物件)[]
(空陣列)" "
(含空格的字串)JS 只有一種數字型別,就是 number
而已,不論是處理二進位、八進位甚至十六進位數字,都是一樣的方法。
parseInt()
函式將字串轉為整數。+
、-
、*
、/
、%
等算術。isNaN()
: 函式,檢查是否是數值。isFinite()
: 函式,檢查是否為有限數值。Infinity
:正無限大。-Infinity
:負無限大。NaN
:表示無效的數字(Not a number),雖然英文意思「不是數字」,但它依舊屬於 number
數字型別,所以 typeof NaN
的檢測結果會是 number
。NaN
與任何數字作數學運算,結果都是 NaN
。NaN
並不等於任何的數字,包含自己。參考資料:
上一篇:【JS幼幼班】Step.04 基本語法:變數
下一篇:【JS幼幼班】Step.06 基本語法:基本型別(string、symbol)
所有的程式語言都具有「資料型別」和「資料結構」的設計。
在 JavaScript 中,分為兩大類資料型別。
「基本型別 Primitive Type」:
null
(空值)undefined
(未定義值)boolean
(布林)number
(數字)string
(字串)symbol
(符號) - ES6 新增「物件型別 Object Type」:
object
(物件):function
(函數)array
(陣列)date
(日期)regExp
(正規表達式)知道資料的型別,才能知道值屬於什麼類型,可以支援哪些操作。
簡單舉例:
a = 1 + 1
如果沒有給予值 1
型別的話,電腦就會無法辨識 a
的結果到底是要用數字相加( 1 + 1 等於 2 ),還是字串相加(文字 1 + 文字 1 等於文字 11 )。
空值分為兩種,兩者都是特殊關鍵字keyword,但表示的意義不同:
null
:表示變數「有定義」值,只是該值為空的,表示沒有結果的操作。undefined
:表示變數「沒有定義」值或「未指定」值,所以你無法使用。一般來說,明確使用 null
表示空值比較好,因為若使用 undefined
表示空值,會被誤以為是忘了定義值。
曾經看過一個有趣的形容,可能讓新手們更容易了解其中的意義:
空字串 : 裝水的杯子今天沒裝水。
null : 沒有杯子。
undefined : 連是不是杯子都不知道。
布林只有兩個值,表示邏輯上的「真」或「假」,在真假判斷式中,所有東西都可以轉換為布林值:
布林值 | 邏輯判斷 | 特殊值判定 |
---|---|---|
true |
真 | {} 、[] 、" " |
false |
假 | 0 、NaN 、'' 、null 、undefined |
不過我們很少直接寫出 true
或 false
,而是會撰寫條件式來改變程式執行流程。
轉型 falsy、truthy
Boolean(value)
去把值轉型為布林值。false
的,稱為 「falsy
」值,而變成 true
的,則叫 「truthy
」值。只有以下這 8 個特殊值透過轉型就會變成 false
,除此之外都是 true
:
false
0
-0
NaN
''
(單引號空字串)""
(雙引號空字串)null
undefined
另外還有幾個特殊值要注意,它是屬於 true
:
{}
(空物件)[]
(空陣列)" "
(含空格的字串)JS 只有一種數字型別,就是 number
而已,不論是處理二進位、八進位甚至十六進位數字,都是一樣的方法。
parseInt()
函式將字串轉為整數。+
、-
、*
、/
、%
等算術。isNaN()
: 函式,檢查是否是數值。isFinite()
: 函式,檢查是否為有限數值。Infinity
:正無限大。-Infinity
:負無限大。NaN
:表示無效的數字(Not a number),雖然英文意思「不是數字」,但它依舊屬於 number
數字型別,所以 typeof NaN
的檢測結果會是 number
。NaN
與任何數字作數學運算,結果都是 NaN
。NaN
並不等於任何的數字,包含自己。參考資料:
上一篇:【JS幼幼班】Step.04 基本語法:變數
下一篇:【JS幼幼班】Step.06 基本語法:基本型別(string、symbol)
物件導向:
以物件 Object
為主的設計方法。把相關的變數跟函數打包在一起,放在同一個物件裡面執行。好處是程式碼易懂好維護,彈性擴展且可重複利用。
動態型別:
變數或常數不需要綁定或定義它的型別(或稱型態),只需要指定它的值。在程式執行期間,會自動根據賦予變數的值,去判斷這個變數的資料型別,然後記錄下來。
弱型別:
指對型別檢查的嚴格程度很弱,僅能嚴格的區分指令和資料。說白一點就是,允許編譯器或直譯器自作主張的容許隱性型別轉換。
接下來正式進入 JS 的基本語法。
變數主要用於方便存取值,且因為 JS 是弱型別的關係,變數本身不帶有型別的資訊,而是讓編譯器或直譯器自己決定。
其實我們國中數學早就教過變數、常數和函數了,什麼 x
、y
、f(x)
之類的可怕回憶,只是 1-20 年後的現在才驚覺派上用場。
通通忘了嗎?沒關係,我也早就忘了XD...先用一張簡單的圖來解釋變數:
可以看到求包養紙箱裝著貓咪,紙箱指的就是「變數 Variable」,貓咪就是「值 Value」。
這樣是不是變得很容易理解變數的概念呢!
作用域指的是變數或常數的定義,與述句被存取到的範圍,其作用範圍可區分為「全域」和「本地端」。作用域規定了如何去找尋變數,也就是確定當前取得變數的權限。
在 JS 中,用來宣告「變數 Variable」與「常數 Constant」的關鍵字有三個,分別是 var
或 let
或 const
。
ES6 之前,宣告變數的關鍵字只有 var
,而且因為只能用「函數 Function」產生作用域,也就是只有使用函數才能劃出一個本地端的作用範圍,其他的區塊像 if
、for
、switch
、while
等,雖然有使用區塊述句 ({...})
,但卻無法界定出作用域。
ES6 之後,則多了「區塊 Block」作用域這個新的方法。每個函數內部有自己的作用域,出了作用域就無法存取函數內定義的變數。而區塊作用域可使用大括號 {}
去定義區塊範圍,且用新的關鍵字 let
或 const
去宣告區塊作用域的變數或常數。
簡單來說,當你在函數「外」宣告變數,它就會變成「全域變數」,而且是在程式碼裡的任何地方都可以被存取得到。反之,在函數「內」宣告則稱為「區域變數」,就是只作用在當前區塊而已。
關鍵字 | 宣告變數/常數 | 作用域 | 可否變動 | 版本 | 特性 |
---|---|---|---|---|---|
var |
全域變數 | 全域、函數 | 可 | ES5 | 1.宣告全域變數,或在「函數內」宣告而不管區塊範圍。 2.容易汙染全域,應避免使用。 |
let |
區域變數 | 區塊 | 可 | ES6 | 1.宣告區域變數的作用域只能在宣告的「區塊」中執行。 2.初始值可選擇性的設定。 |
const |
常數 | 區塊 | 不可 | ES6 | 1.宣告常數的作用域可以是「全域」,或在宣告的「區塊」中。 2.宣告後就不能再作修改,也不能重複宣告,且永遠存在。 |
語法:
var myFirstName = 'Nancy';
let myLastName = 'Lin';
const myFullName = 'Nancy Lin';
語法說明:
var
或 let
或 const
等關鍵字,依需求來宣告一個變數或常數。=
(賦值運算子)來賦予一個值給變數,值可以是任何型別(如:字串、數字、布林等)。而 =
並非數學中的等於或相等,而是賦予或指定的意思。;
結束整個語句。變數命名規則:
0-9
。_
、錢字符號 $
,但不可有其他標點符號、特殊字元或空白。x
和 X
兩個是不一樣的變數名)。myFirstName
、someObject
)。參考資料:
上一篇:【JS幼幼班】Step.03 JavaScript 的基本概念
下一篇:【JS幼幼班】Step.05 基本語法:型別(空值、boolean、number)
物件導向:
以物件 Object
為主的設計方法。把相關的變數跟函數打包在一起,放在同一個物件裡面執行。好處是程式碼易懂好維護,彈性擴展且可重複利用。
動態型別:
變數或常數不需要綁定或定義它的型別(或稱型態),只需要指定它的值。在程式執行期間,會自動根據賦予變數的值,去判斷這個變數的資料型別,然後記錄下來。
弱型別:
指對型別檢查的嚴格程度很弱,僅能嚴格的區分指令和資料。說白一點就是,允許編譯器或直譯器自作主張的容許隱性型別轉換。
接下來正式進入 JS 的基本語法。
變數主要用於方便存取值,且因為 JS 是弱型別的關係,變數本身不帶有型別的資訊,而是讓編譯器或直譯器自己決定。
其實我們國中數學早就教過變數、常數和函數了,什麼 x
、y
、f(x)
之類的可怕回憶,只是 1-20 年後的現在才驚覺派上用場。
通通忘了嗎?沒關係,我也早就忘了XD...先用一張簡單的圖來解釋變數:
可以看到求包養紙箱裝著貓咪,紙箱指的就是「變數 Variable」,貓咪就是「值 Value」。
這樣是不是變得很容易理解變數的概念呢!
作用域指的是變數或常數的定義,與述句被存取到的範圍,其作用範圍可區分為「全域」和「本地端」。作用域規定了如何去找尋變數,也就是確定當前取得變數的權限。
在 JS 中,用來宣告「變數 Variable」與「常數 Constant」的關鍵字有三個,分別是 var
或 let
或 const
。
ES6 之前,宣告變數的關鍵字只有 var
,而且因為只能用「函數 Function」產生作用域,也就是只有使用函數才能劃出一個本地端的作用範圍,其他的區塊像 if
、for
、switch
、while
等,雖然有使用區塊述句 ({...})
,但卻無法界定出作用域。
ES6 之後,則多了「區塊 Block」作用域這個新的方法。每個函數內部有自己的作用域,出了作用域就無法存取函數內定義的變數。而區塊作用域可使用大括號 {}
去定義區塊範圍,且用新的關鍵字 let
或 const
去宣告區塊作用域的變數或常數。
簡單來說,當你在函數「外」宣告變數,它就會變成「全域變數」,而且是在程式碼裡的任何地方都可以被存取得到。反之,在函數「內」宣告則稱為「區域變數」,就是只作用在當前區塊而已。
關鍵字 | 宣告變數/常數 | 作用域 | 可否變動 | 版本 | 特性 |
---|---|---|---|---|---|
var |
全域變數 | 全域、函數 | 可 | ES5 | 1.宣告全域變數,或在「函數內」宣告而不管區塊範圍。 2.容易汙染全域,應避免使用。 |
let |
區域變數 | 區塊 | 可 | ES6 | 1.宣告區域變數的作用域只能在宣告的「區塊」中執行。 2.初始值可選擇性的設定。 |
const |
常數 | 區塊 | 不可 | ES6 | 1.宣告常數的作用域可以是「全域」,或在宣告的「區塊」中。 2.宣告後就不能再作修改,也不能重複宣告,且永遠存在。 |
語法:
var myFirstName = 'Nancy';
let myLastName = 'Lin';
const myFullName = 'Nancy Lin';
語法說明:
var
或 let
或 const
等關鍵字,依需求來宣告一個變數或常數。=
(賦值運算子)來賦予一個值給變數,值可以是任何型別(如:字串、數字、布林等)。而 =
並非數學中的等於或相等,而是賦予或指定的意思。;
結束整個語句。變數命名規則:
0-9
。_
、錢字符號 $
,但不可有其他標點符號、特殊字元或空白。x
和 X
兩個是不一樣的變數名)。myFirstName
、someObject
)。參考資料:
上一篇:【JS幼幼班】Step.03 JavaScript 的基本概念
下一篇:【JS幼幼班】Step.05 基本語法:型別(空值、boolean、number)
JavaScript 最主要的作用在於幫網頁加上行為,這些行為撰寫成程式指令,稱作述句。而述句定義了 JS 的主要語法,通常使用一個或多個關鍵字來表達程式要執行的一些動作,來告訴瀏覽器要做什麼事情。
運算式則定義了程式的邏輯運算原理,並與各種型式的符號、關鍵字組成述句,且以分號 ;
標示為一段述句的結束,表示 JS 程式中一段可執行單位。預設情況下,程式會由上至下、由左到右依序逐行執行,直到最後一行執行完畢。
英文 | 國家 | 用語翻譯 | 產生值 | 說明 |
---|---|---|---|---|
Statement | 台灣、香港 | 述句、語句、陳述式 | 不會 | 相當於一個完整的句子。 |
中國 | 語句 | |||
Expression | 台灣、香港 | 運算式、表達式 | 會 | 類似一個句子的某部分片段。 |
中國 | 表達式 |
;
】分號可以作為述句的結尾,也可以說是運算式之間的分隔,而分號是可選擇加或不加。
我們在上一篇文章已經練習過 alert('這是我的第一個 JavaScript');
這樣的句子了,其實我們還可以編寫更多甚至任意數量的述句,而多個述句之間可以用分號來進行分割。
例如,我們將上面的字串拆成兩組彈跳視窗,並用分號 ;
分隔:
alert('這是我的第一個');alert('JavaScript');
但通常每個述句結束,我們會將其斷行,這樣可以更順暢的閱讀程式碼:
alert('這是我的第一個');
alert('JavaScript');
但如果我們在斷行的時候,不小心忘了加上分號怎麼辦?
alert('這是我的第一個')
alert('JavaScript');
可以看到第一行忘了加分號,但執行時卻不會造成解析錯誤,是因為 JS 容許這樣的錯誤。原因是 JS 會幫我們自動補上分號,正確來說是語法解析器的 ASI ( Automatic Semicolon Insertion自動分號插入) 斷行解讀,並不是實際上插入分號。
只是省略分號可能會讓 JS 誤解你意思而造成程式錯誤,而這種情況下發生的錯誤是很難被找到和解決的,尤其是在新手身上更容易發生。所以官方推薦,還是在每個述句結尾自行加上分號,以防止一些潛在的問題。
不過加或不加分號,早就是 JS 工程師們長久以來的戰爭了,想了解更詳細的分號戰爭,可參閱文末參考資料。
空格(Space)、Tab鍵或換行符號(Newline Characters),在 JS 中都稱為「空白」。當程式碼在解析時,會忽略所有的空白位元,所以當你在程式碼中添加空白,是可以增加程式的可讀性的。如:
c=a+b*2;
var myName='Nancy';
var yourPets=['dog','cat','rabbit'];
和下面的程式碼對照,其實兩者是一樣的意思。
而且在運算子(=
、+
、-
、*
、/
)旁邊增加空格或斷行,其實程式碼會更好閱讀。
c = a + b * 2;
var myName = 'Nancy';
var yourPets = [
'dog',
'cat',
'rabbit'
];
如果想用多個英文單字取名,建議使用「駝峰式大小寫Camel Case」命名,規則是所有英文單字相連,第一個單字的首字母是小寫,其他相連的單字首字母為大寫,又稱為「小駝峰命名」,如:someObject
或 myFirstName
。不過這種命名規則可當作是一種慣例,非絕對或強制,主要目的是增加識別和可讀性。
// 不好的命名 bad
var myfirstname = 'Nancy';
var my_first_name = 'Nancy';
var MYFIRSTNAME = 'Nancy';
var MY_FIRST_NAME = 'Nancy';
p.s:如果每個工程師都像上面那樣,各自有喜愛的命名規則,只會造成團隊或後續維護者閱讀不易,也會讓人無所適從。
// 好的命名 good
var myFirstName = 'Nancy';
p.s:統一大家的命名規則,可以增加程式的可讀性。
一個好的命名能完整描述出它所代表的含義,所以如果命名夠清晰的話,其實是不需再增加註解給它。
// 不好的命名 bad
var a = 5,
b = 10;
console.log(a + b);
p.s:今天很開心的隨便取個 abc
,明天肯定你就忘了它是幹嘛用的,除非你有多下註解說明 a
和 b
指的是什麼。但是即使你註解過了,也不保證這名字在同一支或是別支 JS 檔案沒使用過,更別說其他接手維護的工程師想飛奔過來打你了。
// 好的命名 good
var milkTeaPrice = 20,
sandwichPrice = 15;
console.log(milkTeaPrice + sandwichPrice);
p.s:由上面的變數名稱,很清楚就能明白這是要算奶茶和三明治的總價,連註解都省了。
常數命名
常數可用全大寫命名,單字之間以 _
連接,又稱為「蛇形命名法Snake Case」。在 ES6 之前還沒有 const
指令來宣告常數,只能用 var
宣告,會無法判斷宣告的是變數還是常數,通常用此方法來區別一個變數是否為常數。
var ONE_DAY = SECONDS * MINUTES * HOURS; // ES6 之前,常數的宣告方法
const oneDay = seconds * minutes * hours; // ES6 之後,可直接使用 const 宣告常數
每種程式語言都規定了自己的一套保留字,編寫程式時,在命名識別字名稱必須避開使用保留字。因為保留字往往是具有語法功能的關鍵字,若是以此為名,將會造成程式執行錯誤。因為當瀏覽器開始執行時,該識別字會被程式判斷成語法用的關鍵字,程式會搞不懂你要它做什麼指令或對象是誰,進而導致程式執行衝突,當然 Javascript 也是如此!
識別字就是程式設計師在程式中依需求而自己取的名字(如:變數名、函數名、物件名、對象名等),通常識別字的命名會以具有意義的英文單字為主。例:
var myFirstName = 'Nancy'; // "myFirstName" 就是識別字
var myAge = 18; // "myAge" 就是識別字
取名規則:
可用
Unicode
符號(包含中文、日文、韓文等亞洲字元),長度或大小寫不限,但最通用的還是 26 個英文字母為主,可加上數字、底線符號 _
及金錢符號 $
作為組合。不可用
識別字的第一個字元 絕對不可用數字 0-9
開始,因為數字會先被當成字面常數處理。但第二個字元後就沒有限制,可以用英文、數字或任何 Unicode
符號。
// 錯誤的命名 bad
2mail、room#、this、button
// 正確的命名 good
userName、some_Obj、identifier1、_sys_val、$change、身高、にほんご
保留字指在高級語言中已經定義過的字,有點像是為將來的關鍵字而保留的單字。因此保留字不能被用作變數名、函數名或值的名字等,簡單來說,就是使用者不能再使用這些單字作為命名使用。
JS 的保留字包含「關鍵字Keyword」、「未來保留字Future Reserved Word」、「字面常數Literal」。
1.關鍵字 Keyword
關鍵字就是具有語法功能的單字,且不可拿來作用識別字命名使用。
下面就是舊版 ES3 加上 ES5、ES6 新增的關鍵字一併整理入表,當然其中包含後來 ES5、ES6 刪除的字,最好也不要使用。因為即使已經被 ES5、ES6 刪除,但並非所有瀏覽器都完全支援 ES5、ES6,所以依然建議不使用。
2.未來保留字 Future Reserved Word
在 ECMAScript 規格中,有些關鍵字沒有特殊功能,但在未來某個時間可能會加上而變成新的關鍵字。所以那些關鍵字不能當成識別字使用,不論在嚴格模式和非嚴格模式中均不能用。
3.字面常數Literal
字面常數只有 3 個,分別是 null
、true
、false
。
大小寫敏感
JS 程式碼是對大小寫敏感的,無論是變數、函數或物件名稱等,為了避免輸入混亂和語法錯誤,建議採用小寫字符編寫程式碼。
如:變數名 lastname
和 lastName
是兩個不同的變數,alert()
寫成 Alert()
程式結果是會產生錯誤。
var name = 'Robin Wieruch';
var Name = 'Dennis Wieruch';
var NAME = 'Thomas Wieruch';
console.log(name); // 回傳 "Robin Wieruch"
console.log(Name); // 回傳 "Dennis Wieruch"
console.log(NAME); // 回傳 "Thomas Wieruch"
【程式碼過長,盡量不使用斷行】
有些工程師為了達到最佳的程式可讀性,遇到程式碼過長或是字串過長的狀況,便會將其斷行處理。而程式碼和字串是如何斷行的?
1.一般如果程式碼過長,想要斷行的最佳位置是在「運算子後」直接斷行。如下:
原始碼
document.getElementById("demo").innerHTML = "Nice to meet you.";
斷行後
document.getElementById("demo").innerHTML =
"Nice to meet you.";
但你不可使用跳脫字元 \
在程式碼之間斷行,會出現錯誤訊息:如下:
2.若是字串過長的話,直接斷行可能會導致語法錯誤,因此要在字串斷行後的每行結尾加上 \
代表斷行。注意,\
後面不能輸入空白或其他字元。如下:
原始碼
var str = "Hello! I am Johnson, Nice to meet you. Your eyes is so beautiful.";
斷行後
var str = "Hello! \
I am Johnson, \
Nice to meet you. \
Your eyes is so beautiful.
";
雖然儘管 JS 允許這樣做,但如果在 \
之後出現任何尾隨空格,那麼它就會導致棘手的錯誤,而且這個錯誤對新手來說不太明顯,因此不建議使用。
【註解 Comments】
用於不被程式執行原始碼或說明文字。
在後期維護,可讓維護人員更清楚此程式的撰寫邏輯,或相關參數是什麼意思,分為以下兩種註解方法:
語法 | 名詞 | 說明 |
---|---|---|
// |
單行註解 | 兩個斜線右方的文字,程式不執行 |
/* */ |
多行註解 | 放在/* 和*/ 中間的文字,程式不執行(符號可跨行) |
單行註解寫法:
//這是單行註解:
alert("Hello World!");
多行註解寫法:
/* 這是多行註解:
* 求圓形面積
* @param r {number} 圓的半徑
* @returns {number} 圓的面積
*/
function getArea (r) {
return Math.PI * r * r;
}
不過註解也不要過度濫用,這樣會造成程式檔案肥大,降低讀取效能,畢竟它只是幫助你快速理解程式碼的輔助工具而已,別把它當作文在寫阿 XD。
參考資料:
上一篇:【JS幼幼班】Step.02 寫下你人生中第一個 JavaScript 吧
下一篇:【JS幼幼班】Step.04 基本語法:變數
JavaScript 最主要的作用在於幫網頁加上行為,這些行為撰寫成程式指令,稱作述句。而述句定義了 JS 的主要語法,通常使用一個或多個關鍵字來表達程式要執行的一些動作,來告訴瀏覽器要做什麼事情。
運算式則定義了程式的邏輯運算原理,並與各種型式的符號、關鍵字組成述句,且以分號 ;
標示為一段述句的結束,表示 JS 程式中一段可執行單位。預設情況下,程式會由上至下、由左到右依序逐行執行,直到最後一行執行完畢。
英文 | 國家 | 用語翻譯 | 產生值 | 說明 |
---|---|---|---|---|
Statement | 台灣、香港 | 述句、語句、陳述式 | 不會 | 相當於一個完整的句子。 |
中國 | 語句 | |||
Expression | 台灣、香港 | 運算式、表達式 | 會 | 類似一個句子的某部分片段。 |
中國 | 表達式 |
;
】分號可以作為述句的結尾,也可以說是運算式之間的分隔,而分號是可選擇加或不加。
我們在上一篇文章已經練習過 alert('這是我的第一個 JavaScript');
這樣的句子了,其實我們還可以編寫更多甚至任意數量的述句,而多個述句之間可以用分號來進行分割。
例如,我們將上面的字串拆成兩組彈跳視窗,並用分號 ;
分隔:
alert('這是我的第一個');alert('JavaScript');
但通常每個述句結束,我們會將其斷行,這樣可以更順暢的閱讀程式碼:
alert('這是我的第一個');
alert('JavaScript');
但如果我們在斷行的時候,不小心忘了加上分號怎麼辦?
alert('這是我的第一個')
alert('JavaScript');
可以看到第一行忘了加分號,但執行時卻不會造成解析錯誤,是因為 JS 容許這樣的錯誤。原因是 JS 會幫我們自動補上分號,正確來說是語法解析器的 ASI ( Automatic Semicolon Insertion自動分號插入) 斷行解讀,並不是實際上插入分號。
只是省略分號可能會讓 JS 誤解你意思而造成程式錯誤,而這種情況下發生的錯誤是很難被找到和解決的,尤其是在新手身上更容易發生。所以官方推薦,還是在每個述句結尾自行加上分號,以防止一些潛在的問題。
不過加或不加分號,早就是 JS 工程師們長久以來的戰爭了,想了解更詳細的分號戰爭,可參閱文末參考資料。
空格(Space)、Tab鍵或換行符號(Newline Characters),在 JS 中都稱為「空白」。當程式碼在解析時,會忽略所有的空白位元,所以當你在程式碼中添加空白,是可以增加程式的可讀性的。如:
c=a+b*2;
var myName='Nancy';
var yourPets=['dog','cat','rabbit'];
和下面的程式碼對照,其實兩者是一樣的意思。
而且在運算子(=
、+
、-
、*
、/
)旁邊增加空格或斷行,其實程式碼會更好閱讀。
c = a + b * 2;
var myName = 'Nancy';
var yourPets = [
'dog',
'cat',
'rabbit'
];
如果想用多個英文單字取名,建議使用「駝峰式大小寫Camel Case」命名,規則是所有英文單字相連,第一個單字的首字母是小寫,其他相連的單字首字母為大寫,又稱為「小駝峰命名」,如:someObject
或 myFirstName
。不過這種命名規則可當作是一種慣例,非絕對或強制,主要目的是增加識別和可讀性。
// 不好的命名 bad
var myfirstname = 'Nancy';
var my_first_name = 'Nancy';
var MYFIRSTNAME = 'Nancy';
var MY_FIRST_NAME = 'Nancy';
p.s:如果每個工程師都像上面那樣,各自有喜愛的命名規則,只會造成團隊或後續維護者閱讀不易,也會讓人無所適從。
// 好的命名 good
var myFirstName = 'Nancy';
p.s:統一大家的命名規則,可以增加程式的可讀性。
一個好的命名能完整描述出它所代表的含義,所以如果命名夠清晰的話,其實是不需再增加註解給它。
// 不好的命名 bad
var a = 5,
b = 10;
console.log(a + b);
p.s:今天很開心的隨便取個 abc
,明天肯定你就忘了它是幹嘛用的,除非你有多下註解說明 a
和 b
指的是什麼。但是即使你註解過了,也不保證這名字在同一支或是別支 JS 檔案沒使用過,更別說其他接手維護的工程師想飛奔過來打你了。
// 好的命名 good
var milkTeaPrice = 20,
sandwichPrice = 15;
console.log(milkTeaPrice + sandwichPrice);
p.s:由上面的變數名稱,很清楚就能明白這是要算奶茶和三明治的總價,連註解都省了。
常數命名
常數可用全大寫命名,單字之間以 _
連接,又稱為「蛇形命名法Snake Case」。在 ES6 之前還沒有 const
指令來宣告常數,只能用 var
宣告,會無法判斷宣告的是變數還是常數,通常用此方法來區別一個變數是否為常數。
var ONE_DAY = SECONDS * MINUTES * HOURS; // ES6 之前,常數的宣告方法
const oneDay = seconds * minutes * hours; // ES6 之後,可直接使用 const 宣告常數
每種程式語言都規定了自己的一套保留字,編寫程式時,在命名識別字名稱必須避開使用保留字。因為保留字往往是具有語法功能的關鍵字,若是以此為名,將會造成程式執行錯誤。因為當瀏覽器開始執行時,該識別字會被程式判斷成語法用的關鍵字,程式會搞不懂你要它做什麼指令或對象是誰,進而導致程式執行衝突,當然 Javascript 也是如此!
識別字就是程式設計師在程式中依需求而自己取的名字(如:變數名、函數名、物件名、對象名等),通常識別字的命名會以具有意義的英文單字為主。例:
var myFirstName = 'Nancy'; // "myFirstName" 就是識別字
var myAge = 18; // "myAge" 就是識別字
取名規則:
可用
Unicode
符號(包含中文、日文、韓文等亞洲字元),長度或大小寫不限,但最通用的還是 26 個英文字母為主,可加上數字、底線符號 _
及金錢符號 $
作為組合。不可用
識別字的第一個字元 絕對不可用數字 0-9
開始,因為數字會先被當成字面常數處理。但第二個字元後就沒有限制,可以用英文、數字或任何 Unicode
符號。
// 錯誤的命名 bad
2mail、room#、this、button
// 正確的命名 good
userName、some_Obj、identifier1、_sys_val、$change、身高、にほんご
保留字指在高級語言中已經定義過的字,有點像是為將來的關鍵字而保留的單字。因此保留字不能被用作變數名、函數名或值的名字等,簡單來說,就是使用者不能再使用這些單字作為命名使用。
JS 的保留字包含「關鍵字Keyword」、「未來保留字Future Reserved Word」、「字面常數Literal」。
1.關鍵字 Keyword
關鍵字就是具有語法功能的單字,且不可拿來作用識別字命名使用。
下面就是舊版 ES3 加上 ES5、ES6 新增的關鍵字一併整理入表,當然其中包含後來 ES5、ES6 刪除的字,最好也不要使用。因為即使已經被 ES5、ES6 刪除,但並非所有瀏覽器都完全支援 ES5、ES6,所以依然建議不使用。
2.未來保留字 Future Reserved Word
在 ECMAScript 規格中,有些關鍵字沒有特殊功能,但在未來某個時間可能會加上而變成新的關鍵字。所以那些關鍵字不能當成識別字使用,不論在嚴格模式和非嚴格模式中均不能用。
3.字面常數Literal
字面常數只有 3 個,分別是 null
、true
、false
。
大小寫敏感
JS 程式碼是對大小寫敏感的,無論是變數、函數或物件名稱等,為了避免輸入混亂和語法錯誤,建議採用小寫字符編寫程式碼。
如:變數名 lastname
和 lastName
是兩個不同的變數,alert()
寫成 Alert()
程式結果是會產生錯誤。
var name = 'Robin Wieruch';
var Name = 'Dennis Wieruch';
var NAME = 'Thomas Wieruch';
console.log(name); // 回傳 "Robin Wieruch"
console.log(Name); // 回傳 "Dennis Wieruch"
console.log(NAME); // 回傳 "Thomas Wieruch"
【程式碼過長,盡量不使用斷行】
有些工程師為了達到最佳的程式可讀性,遇到程式碼過長或是字串過長的狀況,便會將其斷行處理。而程式碼和字串是如何斷行的?
1.一般如果程式碼過長,想要斷行的最佳位置是在「運算子後」直接斷行。如下:
原始碼
document.getElementById("demo").innerHTML = "Nice to meet you.";
斷行後
document.getElementById("demo").innerHTML =
"Nice to meet you.";
但你不可使用跳脫字元 \
在程式碼之間斷行,會出現錯誤訊息:如下:
2.若是字串過長的話,直接斷行可能會導致語法錯誤,因此要在字串斷行後的每行結尾加上 \
代表斷行。注意,\
後面不能輸入空白或其他字元。如下:
原始碼
var str = "Hello! I am Johnson, Nice to meet you. Your eyes is so beautiful.";
斷行後
var str = "Hello! \
I am Johnson, \
Nice to meet you. \
Your eyes is so beautiful.
";
雖然儘管 JS 允許這樣做,但如果在 \
之後出現任何尾隨空格,那麼它就會導致棘手的錯誤,而且這個錯誤對新手來說不太明顯,因此不建議使用。
【註解 Comments】
用於不被程式執行原始碼或說明文字。
在後期維護,可讓維護人員更清楚此程式的撰寫邏輯,或相關參數是什麼意思,分為以下兩種註解方法:
語法 | 名詞 | 說明 |
---|---|---|
// |
單行註解 | 兩個斜線右方的文字,程式不執行 |
/* */ |
多行註解 | 放在/* 和*/ 中間的文字,程式不執行(符號可跨行) |
單行註解寫法:
//這是單行註解:
alert("Hello World!");
多行註解寫法:
/* 這是多行註解:
* 求圓形面積
* @param r {number} 圓的半徑
* @returns {number} 圓的面積
*/
function getArea (r) {
return Math.PI * r * r;
}
不過註解也不要過度濫用,這樣會造成程式檔案肥大,降低讀取效能,畢竟它只是幫助你快速理解程式碼的輔助工具而已,別把它當作文在寫阿 XD。
參考資料:
上一篇:【JS幼幼班】Step.02 寫下你人生中第一個 JavaScript 吧
下一篇:【JS幼幼班】Step.04 基本語法:變數
1.放在 <head>
和 </head>
之間:
2.放在 HTML 最後面, </body>
結尾標籤之前:(此方式最推薦)
在前一個章節就提過 考試會考 的內容:
瀏覽器讀取 HTML 的順序是由上而下讀取,當讀到 <script>
標籤或 JS 檔案時,網頁渲染會暫停,這時瀏覽器會先把 JS 腳本先執行完,再渲染後面的內容。所以 JS 腳本或檔案要放在 HTML 的最後 </body>
結束標籤之前,才不會導致頁面被中斷讀取過久而影響使用者體驗。
而一個 HTML 裡面可以同時存在很多個 JS 或 JQ 腳本,所以優化瀏覽器最有效率的寫法,當然是把 JS、JQ 腳本或引用的檔案,放在 HTML 最後面 </body>
結尾標籤之前囉。
把 JS 程式碼寫在 <script>
和 </script>
標籤裡面
舊版 HTML 寫法:
必須在 <script>
標籤內指定 type
屬性,且規定腳本的 MIME 類型為 text/javascript
<script type="text/javascript">
var a = 5;
console.log(a);
</script>
新版 HTML5 寫法:
<script>
會自動執行並忽略 type
屬性,不需要再多寫 MIME 類型。
<script>
var a = 5;
console.log(a);
</script>
把 JS 程式碼寫在獨立檔案,以絕對路徑讀取檔案,供 HTML 引入執行。
<script src="js/xxxxx.js"></script>
或是一些含有 JS 或 jQuery(以下簡稱 JQ) 特效的官方 CDN 等,才需要用外部連結引入,如:
<script src="https://code.jquery.com/jquery-2.2.4.js"></script>
早期網頁還沒出現 jQuery 之前,在 HTML 標籤內混寫 JS 語法是當時傳統的做法,你也許見過下面的寫法:
<input type="text" name="date" onchange="validateDate()">
或
<div onclick="window.open('test.html','_self');" class="btn"></div>
將 JS 嵌入 HTML 標籤裡使用,會導致網站原始碼不易閱讀及維護,原因是 HTML 標籤通常是描述檔案的排版結構,而非網頁操作的程式行為。而「非侵入式 JavaScript」方案,則是以程式碼另外獨立撰寫其需要對應的事件,而不是和網頁元素內嵌在一起。在 JS 腳本事件中的相關元素,在 HTML 標籤中則改用簡單的屬性參數,如:用 id屬性、 class名稱 或 value值等,作為程式碼回應的參數進行執行需要的設定,尤其對網頁內擁有許多相同功能需要傳輸或設定,更是方便許多。
如果把上面範例第一行的 <input>
語法,改為非侵入式寫法,整句話的語意會更加清晰。
<input type="text" name="date" id="date">
<script>
window.addEventListener('DOMContentLoaded',function(event){
document.getElementById('date').addEventListener('change',validateDate);
});
</script>
註:<input>
內的 id
元素就是 JS 腳本事件中對應的參數。
上述 4 種方式各有其用處,除非 JS 程式碼量很短,否則利用外部引入的方式,不僅易於維護,也可在重覆瀏覽時用快取節省網頁載入時間,還更利於維護與修改。若頁面同時存在 JS 和 JQ 檔案,則需要分開引入,以免造成維護上的困難。
以上就是輕鬆學習 JavaScript 的建置方法,接下來就開始教你怎麼寫 JS 吧!
首先打開你的網頁編輯器,如:VS Code、Sublime Text、Atom、Notepad...都可。如果都沒有,可以使用線上編輯器,個人還蠻推薦 CodePen 或 JSBin,畢竟畫面功能直覺,且預覽速度又快,而且 CodePen 免費會員還有存檔功能,及各種大神的作品可以參考。
1.打開 CodePen 之後,不需登入一樣可以使用,請點擊左上方的「Start Coding」按鈕
2.接下來出現有「HTML、CSS、JS」這3個編輯窗格,和一個大大的「預覽」窗格。
如果你的欄位編排方式和我的長得不一樣也沒差,畢竟這是個人喜好。如果想跟我一樣,請按右上方的「Change View」更改你喜歡的編輯方式,滑出一組三選一欄位,請改為中間那個。
3.然後請在右上角的「JS」窗格內寫下以下程式碼。
alert("這是我的第一個 JavaScript");
4.滑鼠游標點擊下方的「預覽」窗格,1-2秒後就可以看到畫面上方跳出一個小視窗,內容寫著:「這是我的第一個 JavaScript」
然後...你就完成了你人生中第一支的 JavaScript了。
如果你是用自己的編輯器,以 VS Code 為例,方法如下:
1.打開 VS Code,點擊 File (檔案) -> New File (新增檔案)。
2.接下來要把從無法辨識的文件改成 html。請在圖的最下排藍色功能列(圖寫1)上,點擊「Plain Text 純文字」,圖上方跳出搜尋列(圖寫2)打上「html」,然後按 Enter 鍵
3.接著在文件內容打上半形的「!」,按 Enter 鍵
4.出現 html5 的標準結構之後,在 <body>
和 </body>
之間打入下方程式碼:
<script>
alert("這是我的第一個 JavaScript");
</script>
如圖:
5.接著點擊 File (檔案) -> Save (儲存),隨便取個 test.html。
6.接著從檔案總管直接雙擊剛儲存的檔案,它便會使用你電腦預設的瀏覽器開啟,這裡以 Google Chrome 瀏覽器為例。你可以看到網頁上方出現一個彈跳視窗,寫著「這是我的第一個 JavaScript」,這樣就完成了。
What?!!!
沒錯,JavaScript 的入門門檻就這麼低,剩下就是要詳加了解它的語法和邏輯運用而已。
其實它還能以很多種不同的方式來顯示,以下再介紹幾個初學者最常使用的簡易寫法:
innerHTML()
寫入 HTML 元素innerHTML 是 W3C 規定的標準寫法,主要是用來取得 HTML 元素或寫入字串到 HTML 的語法,它還有個特性,就是會覆蓋原本寫的內容。另外,它還可以搭配 Element Object 來執行,如語法 getElementById()
(取得 id值 )或 getElementsByName()
(取得 name值 )等,這也是多數人常用來使用網頁互動特效的方法之一,而且幾乎所有主流的瀏覽器都支援此功能。寫法如下:
<div id="Num"></div>
<script>
document.getElementById('Num').innerHTML = 5;
//JS翻譯:把數字 5 寫入到 HTML 標籤內含有 id 叫做 Num 的地方
</script>
你可以使用 CodePen 測試看看,把上方的程式碼,複製貼到 CodePen 左上角的 「HTML」 欄位內,下方的預覽窗格就會出現 5 的數字。
console.log()
寫入瀏覽器控制台。(最多人用這個 Debug 偵錯)幾乎各家瀏覽器都有 console 控制台(或稱「主控台」)的功能,大多都是按 F12,或是在瀏覽器的網頁內容按右鍵,選擇「檢查」或「檢查原始碼」就可以開啟「開發者工具」這個神奇的介面,不管是基礎或資深開發者都需要使用這個無敵好用的偵錯功能。
1.以 Chrome 瀏覽器為例,按 F12,開啟「開發者工具」介面,點擊左上方的「Console」
3.在上圖「Console 控制台」內,看到一個正在閃爍的游標,這時在游標處打入下方程式碼:
console.log(5 + 2);
然後按 Enter
鍵,則會看到下方會自動輸出數字 7。
然後我們又完成了二種寫 JS 的方法了。
以上就是 JavaScript 的超入門建置方式,接下來就是開始進入基本概念和語法囉。
參考資料:
上一篇:【JS幼幼班】Step.01 學習,從「不要害怕」開始
下一篇:【JS幼幼班】Step.03 JavaScript 的基本概念
1.放在 <head>
和 </head>
之間:
2.放在 HTML 最後面, </body>
結尾標籤之前:(此方式最推薦)
在前一個章節就提過 考試會考 的內容:
瀏覽器讀取 HTML 的順序是由上而下讀取,當讀到 <script>
標籤或 JS 檔案時,網頁渲染會暫停,這時瀏覽器會先把 JS 腳本先執行完,再渲染後面的內容。所以 JS 腳本或檔案要放在 HTML 的最後 </body>
結束標籤之前,才不會導致頁面被中斷讀取過久而影響使用者體驗。
而一個 HTML 裡面可以同時存在很多個 JS 或 JQ 腳本,所以優化瀏覽器最有效率的寫法,當然是把 JS、JQ 腳本或引用的檔案,放在 HTML 最後面 </body>
結尾標籤之前囉。
把 JS 程式碼寫在 <script>
和 </script>
標籤裡面
舊版 HTML 寫法:
必須在 <script>
標籤內指定 type
屬性,且規定腳本的 MIME 類型為 text/javascript
<script type="text/javascript">
var a = 5;
console.log(a);
</script>
新版 HTML5 寫法:
<script>
會自動執行並忽略 type
屬性,不需要再多寫 MIME 類型。
<script>
var a = 5;
console.log(a);
</script>
把 JS 程式碼寫在獨立檔案,以絕對路徑讀取檔案,供 HTML 引入執行。
<script src="js/xxxxx.js"></script>
或是一些含有 JS 或 jQuery(以下簡稱 JQ) 特效的官方 CDN 等,才需要用外部連結引入,如:
<script src="https://code.jquery.com/jquery-2.2.4.js"></script>
早期網頁還沒出現 jQuery 之前,在 HTML 標籤內混寫 JS 語法是當時傳統的做法,你也許見過下面的寫法:
<input type="text" name="date" onchange="validateDate()">
或
<div onclick="window.open('test.html','_self');" class="btn"></div>
將 JS 嵌入 HTML 標籤裡使用,會導致網站原始碼不易閱讀及維護,原因是 HTML 標籤通常是描述檔案的排版結構,而非網頁操作的程式行為。而「非侵入式 JavaScript」方案,則是以程式碼另外獨立撰寫其需要對應的事件,而不是和網頁元素內嵌在一起。在 JS 腳本事件中的相關元素,在 HTML 標籤中則改用簡單的屬性參數,如:用 id屬性、 class名稱 或 value值等,作為程式碼回應的參數進行執行需要的設定,尤其對網頁內擁有許多相同功能需要傳輸或設定,更是方便許多。
如果把上面範例第一行的 <input>
語法,改為非侵入式寫法,整句話的語意會更加清晰。
<input type="text" name="date" id="date">
<script>
window.addEventListener('DOMContentLoaded',function(event){
document.getElementById('date').addEventListener('change',validateDate);
});
</script>
註:<input>
內的 id
元素就是 JS 腳本事件中對應的參數。
上述 4 種方式各有其用處,除非 JS 程式碼量很短,否則利用外部引入的方式,不僅易於維護,也可在重覆瀏覽時用快取節省網頁載入時間,還更利於維護與修改。若頁面同時存在 JS 和 JQ 檔案,則需要分開引入,以免造成維護上的困難。
以上就是輕鬆學習 JavaScript 的建置方法,接下來就開始教你怎麼寫 JS 吧!
首先打開你的網頁編輯器,如:VS Code、Sublime Text、Atom、Notepad...都可。如果都沒有,可以使用線上編輯器,個人還蠻推薦 CodePen 或 JSBin,畢竟畫面功能直覺,且預覽速度又快,而且 CodePen 免費會員還有存檔功能,及各種大神的作品可以參考。
1.打開 CodePen 之後,不需登入一樣可以使用,請點擊左上方的「Start Coding」按鈕
2.接下來出現有「HTML、CSS、JS」這3個編輯窗格,和一個大大的「預覽」窗格。
如果你的欄位編排方式和我的長得不一樣也沒差,畢竟這是個人喜好。如果想跟我一樣,請按右上方的「Change View」更改你喜歡的編輯方式,滑出一組三選一欄位,請改為中間那個。
3.然後請在右上角的「JS」窗格內寫下以下程式碼。
alert("這是我的第一個 JavaScript");
4.滑鼠游標點擊下方的「預覽」窗格,1-2秒後就可以看到畫面上方跳出一個小視窗,內容寫著:「這是我的第一個 JavaScript」
然後...你就完成了你人生中第一支的 JavaScript了。
如果你是用自己的編輯器,以 VS Code 為例,方法如下:
1.打開 VS Code,點擊 File (檔案) -> New File (新增檔案)。
2.接下來要把從無法辨識的文件改成 html。請在圖的最下排藍色功能列(圖寫1)上,點擊「Plain Text 純文字」,圖上方跳出搜尋列(圖寫2)打上「html」,然後按 Enter 鍵
3.接著在文件內容打上半形的「!」,按 Enter 鍵
4.出現 html5 的標準結構之後,在 <body>
和 </body>
之間打入下方程式碼:
<script>
alert("這是我的第一個 JavaScript");
</script>
如圖:
5.接著點擊 File (檔案) -> Save (儲存),隨便取個 test.html。
6.接著從檔案總管直接雙擊剛儲存的檔案,它便會使用你電腦預設的瀏覽器開啟,這裡以 Google Chrome 瀏覽器為例。你可以看到網頁上方出現一個彈跳視窗,寫著「這是我的第一個 JavaScript」,這樣就完成了。
What?!!!
沒錯,JavaScript 的入門門檻就這麼低,剩下就是要詳加了解它的語法和邏輯運用而已。
其實它還能以很多種不同的方式來顯示,以下再介紹幾個初學者最常使用的簡易寫法:
innerHTML()
寫入 HTML 元素innerHTML 是 W3C 規定的標準寫法,主要是用來取得 HTML 元素或寫入字串到 HTML 的語法,它還有個特性,就是會覆蓋原本寫的內容。另外,它還可以搭配 Element Object 來執行,如語法 getElementById()
(取得 id值 )或 getElementsByName()
(取得 name值 )等,這也是多數人常用來使用網頁互動特效的方法之一,而且幾乎所有主流的瀏覽器都支援此功能。寫法如下:
<div id="Num"></div>
<script>
document.getElementById('Num').innerHTML = 5;
//JS翻譯:把數字 5 寫入到 HTML 標籤內含有 id 叫做 Num 的地方
</script>
你可以使用 CodePen 測試看看,把上方的程式碼,複製貼到 CodePen 左上角的 「HTML」 欄位內,下方的預覽窗格就會出現 5 的數字。
console.log()
寫入瀏覽器控制台。(最多人用這個 Debug 偵錯)幾乎各家瀏覽器都有 console 控制台(或稱「主控台」)的功能,大多都是按 F12,或是在瀏覽器的網頁內容按右鍵,選擇「檢查」或「檢查原始碼」就可以開啟「開發者工具」這個神奇的介面,不管是基礎或資深開發者都需要使用這個無敵好用的偵錯功能。
1.以 Chrome 瀏覽器為例,按 F12,開啟「開發者工具」介面,點擊左上方的「Console」
3.在上圖「Console 控制台」內,看到一個正在閃爍的游標,這時在游標處打入下方程式碼:
console.log(5 + 2);
然後按 Enter
鍵,則會看到下方會自動輸出數字 7。
然後我們又完成了二種寫 JS 的方法了。
以上就是 JavaScript 的超入門建置方式,接下來就是開始進入基本概念和語法囉。
參考資料:
上一篇:【JS幼幼班】Step.01 學習,從「不要害怕」開始
下一篇:【JS幼幼班】Step.03 JavaScript 的基本概念
在不想被社會淘汰的前提下,於是硬著頭皮捏著覽啪,開始自學了幾個月的 jQuery 和 JS。從免費學習資源 freeCodeCamp、Codecademy、iT邦幫忙大神們的鐵人賽文,加上便宜-百元左右(Udemy、Lidemy鋰學院)或不怎便宜-上千上萬元(六角學院、HiSKIO、Hahow)的付費線上課程,內容從初階到進階,甚至新的ES6語法等都學習完了,jQuery 倒是比較直覺簡單好撰寫,也足以應付網頁上大多需求。
但學習 JavaScript 卻一直都是我的痛點。老實說對它依然一知半解,尤其遇到測驗題就是腦子一片空白,更別說怎麼拆解問題。所以每次看到一堆網路大神說自己曾是零經驗小白,在自學了幾個月之後就變成可上線實戰的工程師,只覺得神屌。或許是我對程式語言的理解力太低,不然就是邏輯或組織架構能力不足,即使實作測驗頂多也只是跟著影片或題目Coding,沒有真正的吸收到如何實際有效運用。
從入門到超想放棄,JavaScript 之所以能夠勸退一堆新手不是沒有道理的。也許我用了不對的方法學習,所以我決定讓自己重新歸0,一邊當作是為自己累積實作經驗,一邊當作是教學相長,希望能給你我帶來一些學習上的助益。
-- 本文正式開始 --
肇始於網景公司(Netscape),由網景工程師 Brendan Eich 在 1995年所發明,據說當初僅花了10天就完成(當然也就造就了不少奇妙的Bug)。最初命名為 Mocha,同年9月改名為 LiveScript,12月又被重新命名為 JavaScript。名字之所以變來變去,是當時網景與昇陽組成的開發聯盟,行銷策略原因只是為了讓這門語言搭上 Java 這個程式語言「熱詞」,才臨時改名為JavaScript,日後這也成為大眾對這門語言有諸多誤解的原因之一。(就像「狗和熱狗」,或「太陽和太陽餅」根本毫無關係,有沒有被騙了很久的感覺...)
早期網頁都是靜態顯示,為了讓網頁更加生動活潑,於是便誕生了 JavaScript。
JS 是一種程式語言,以純文件形式提供「腳本」(即程式內容)。腳本可以直接寫在 html 裡面,或在頁面引用外部連結,並在加載的時候自動執行。
現今的 JS 在瀏覽器、服務端或在有搭載任意 JS 引擎(或稱為「JS 虛擬機」)的設備中皆可執行。
JavaScript 引擎:
它就是理解並執行 JavaScript 程式碼的解釋器,有點像人對語言的處理。
目前市面上主要網頁瀏覽器的 JS 引擎整理如下:
JS 引擎代號 | 瀏覽器/執行環境 | 瀏覽器版本 | 說明 |
---|---|---|---|
V8 | Google Chrome | v1.0~v3.0 | 用C++編寫,開放原始碼 |
V8 | TrifleJS、Node.js...等 | ||
SpiderMonkey | Mozilla Firefox | 1.0~3.0 | 第一款JS引擎 |
TraceMonkey | Mozilla Firefox | 3.5~3.6 | 基於實時編譯的引擎,其中部份代碼取自Tamarin引擎 |
JaegerMonkey | Mozilla Firefox | 4.0以上 | 結合追踪和組合碼技術大幅提高性能,部分技術借鑿了V8、JavaScriptCore、WebKit |
Chakra (JScript引擎) | Microsoft Internet Explorer | 9 (32bit)、10、11 | 用C++編寫,開放原始碼 |
Chakra (JavaScript引擎) | Microsoft Edge | 用C++編寫,開放原始碼 | |
Rhino | HTMLUnit | 用Java編寫,開放原始碼 | |
JavaScriptCore | Apple Safari | 開放原始碼,用於webkit型瀏覽器 | |
Nitro | Apple Safari | 4 | JavaScriptCore 被改寫為SquirrelFish,升級版本為QuirrelFish Extreme,也叫做Nitro |
Linear A | Opera | 4.0~6.1 | |
Linear B | Opera | 7.0~9.2 | |
Futhark | Opera | 9.5~10.2 | |
Carakan | Opera | 10.50以上 | |
KJS,KDE的ECMAScript/JavaScript引擎 | Konqueror | 最初由哈里波頓開發,用於KDE專案瀏覽器 |
JavaScript 是當前網路上最流行,也是唯一被各家瀏覽器所共同支援的程式語言,同時亦是一種跨平台、輕量級、直譯式、物件導向、動態型別、弱型別的腳本語言。這門語言可用於 HTML 和 Web,更可廣泛用於伺服器、桌上型電腦、筆記本電腦、平板電腦和手機等設備。由於它不提供對內存或 CPU 的底層訪問,所以也被稱為一種安全的程式語言。
雖然作為獨立語言並不實用,但它可是為了能簡單嵌入其他產品和應用程式而設計。若寄宿在主體環境時,可以與環境中的物件相連,並以程式控制這些物件。雖然初期是用在網頁互動上,但它已不止局限在瀏覽器,也能應用在伺服端(如node.js)、手機app開發、遊戲開發、互動藝術等等。
JavaScript 是 1996 年創造的,於隔年 1997 年被網景公司提交給 Ecma 國際制定為標準。而 ECMAScript 簡稱 ES,是一種通用的程式語言,由 Ecma 國際在 ECMA-262 進行標準化。從 IE 3.0 開始,很多瀏覽器開始使用 ECMAScript。
所以簡單來說 ES 是 JS 的標準,目的是讓不同瀏覽器之間能根據 spec 版本來實作。類似市面上的電腦鍵盤,上面的字母、符號、方向鍵等,順序排列幾乎都是相同的位置,只是差在外型各有區別,這是因為各廠商皆遵守了相同的標準規範。而 JS 只是其中一種實作和擴充的程式語言,雖然 JS 相容於 ES 規範,但 JS 還提供 ES 未定義的特性。
當 ECMAScript 發布第三版(即 ES3)之後,便成為當時所有瀏覽器支援的程式語言,ES 後面的數字是版本號碼。從 2015 年起,改為以年份命名(如:ECMAScript 2015、ECMAScript 2016、ECMAScript 2017...),而因目前瀏覽器兼容性已漸漸提高,舊的瀏覽器也幾乎快被淘汰,因此最廣泛被使用的版本為改革幅度最大的 ES6 版。
儘管瀏覽器的 JS 引擎都能理解 JS,但有些瀏覽器的理解能力更強,對它的支持度亦不一樣。因此每當新的 ES 發布,JS 並沒有一次性支援所有新特性,這取決於引擎開發者是否有陸續開放新的支援。
ECMAScript Spec 版本演化表:
版本簡稱 | 版本官方名稱 | 說明 |
---|---|---|
ES1 | ECMAScript 1 (1997) | 第一版 |
ES2 | ECMAScript 2 (1998) | 編輯更改 |
ES3 | ECMAScript 3 (1999) | 新增「正規表達式」、try、catch、switch、do-while |
ES4 | ECMAScript 4 | 從未發布 |
ES5 | ECMAScript 5 (2009) | 支持 JSON、新增「嚴格模式」、String.trim()、Array.isArray()、數組迭代等方法、允許對象文字的尾隨逗號 |
ES6 | ECMAScript 2015 | 新增 let 和 const、默認參數值、Array.find()、Array.findIndex() |
ES7 | ECMAScript 2016 | 新增「指數運算符」、Array.includes() |
ES8 | ECMAScript 2017 | 新增「字串填充」、Object.entries()、Object.values()、異步函數、共享內存 |
ES9 | ECMAScript 2018 | 新增 rest、spread、異步迭代、Promise.finally()、在迴圈中使用await、更多「正規表達式」 |
ES10 | ECMAScript 2019 | 新的數據類型 BigInt,更友好的JSON.stringify、新增Array的flat()和flatMap()、String的trimStart()和trimEnd()、Object.fromEntries()、簡化try、catch,修改catch綁定...等 |
ES11 | ECMAScript 2020 | 新增 Promise.allSettled、可選鏈「?」、空值合併運算「??」、動態載入dynamic-import、globalThis |
ES12 | ECMAScript 2021 | 結合邏輯運算符和賦值表達式,新增「數字分隔符」、replaceAll、Promise.any、弱引用WeakRefs、Finalizers、FinalizationRegistry |
網頁的基礎語言架構為 HTML、CSS、JS。看下方圖表就知道了,他們各司其職卻又互相牽動,就像人體構造一樣,少一個都不行。
名稱 | 語言類別 | 負責項目 | 主要功能 |
---|---|---|---|
HTML | 標記語言 | 網頁「結構」(類似骨骼) | 網頁的「靜態」內容 |
CSS | 樣式規則語言 | 網頁「樣式」(類似皮膚外觀) | 「美化」網頁 |
JavaScript | 腳本語言 | 網頁「行為」(類似中樞神經) | 網頁的「動態」內容 |
瀏覽器中的 JS 可以做與網頁操作、用戶交互回應及 Web 伺服器相關的所有事情。
基於使用者的個資或訊息安全,在瀏覽器中的 JS 能力是受限的。目的是防止惡意網頁擷取用戶私人訊息或損害用戶數據。限制如下:
<input>
標籤選擇了硬碟中的文件等。網頁的加載性能,與瀏覽器的渲染機制關係密不可分,身為前端開發人員,必須先搞清楚瀏覽器背後的渲染機制,才能在開發中進行性能優化,所以我們就來了解一下瀏覽器是如何渲染頁面的吧:
首先是我們要讀取一個網站,必須先有它的網址(URL),然後在你的瀏覽器(如:Google Chrome)上打上這段長長的網址。
接著瀏覽器就會進行域名解析,並向服務器發起請求,並得到這個網址內的 HTML、CSS、images、JavaScript等。
然後你的瀏覽器在得到資料後,便會開始解析 html 並構建 DOM(DOM樹),且由上而下依序讀取顯示。
讀到 CSS 資料的時候,就會開始構建 CSSOM(CSS樹),並和 DOM 一起生成 Render Tree(渲染樹),計算出每個節點在螢幕中的位置,然後根據渲染樹對頁面進行渲染。
當讀到 JS 檔案時,網頁渲染會暫停,這時瀏覽器會先把 JS 腳本先執行完,再渲染後面的內容。所以 JS 腳本或檔案要放在 HTML 的最後 </body>
結束標籤之前,才不會導致頁面被中斷讀取過久而影響使用者體驗。(很重要,考試會考)
最後解譯器可以透過它的 JS 引擎幫我們編譯,並且即時顯示出效果,並透過顯卡把完整的頁面顯示到螢幕上,也就是我們打開網頁讀個幾秒後看到的樣子。
至於 DOM、CSSOM、渲染樹是什麼?裡面有相當多的專有名詞可以探討,但非本文要談論的重點。因為範圍有點太廣了,有興趣的可以到下面的參考資料補足你想知道的。
參考資料:
在不想被社會淘汰的前提下,於是硬著頭皮捏著覽啪,開始自學了幾個月的 jQuery 和 JS。從免費學習資源 freeCodeCamp、Codecademy、iT邦幫忙大神們的鐵人賽文,加上便宜-百元左右(Udemy、Lidemy鋰學院)或不怎便宜-上千上萬元(六角學院、HiSKIO、Hahow)的付費線上課程,內容從初階到進階,甚至新的ES6語法等都學習完了,jQuery 倒是比較直覺簡單好撰寫,也足以應付網頁上大多需求。
但學習 JavaScript 卻一直都是我的痛點。老實說對它依然一知半解,尤其遇到測驗題就是腦子一片空白,更別說怎麼拆解問題。所以每次看到一堆網路大神說自己曾是零經驗小白,在自學了幾個月之後就變成可上線實戰的工程師,只覺得神屌。或許是我對程式語言的理解力太低,不然就是邏輯或組織架構能力不足,即使實作測驗頂多也只是跟著影片或題目Coding,沒有真正的吸收到如何實際有效運用。
從入門到超想放棄,JavaScript 之所以能夠勸退一堆新手不是沒有道理的。也許我用了不對的方法學習,所以我決定讓自己重新歸0,一邊當作是為自己累積實作經驗,一邊當作是教學相長,希望能給你我帶來一些學習上的助益。
-- 本文正式開始 --
肇始於網景公司(Netscape),由網景工程師 Brendan Eich 在 1995年所發明,據說當初僅花了10天就完成(當然也就造就了不少奇妙的Bug)。最初命名為 Mocha,同年9月改名為 LiveScript,12月又被重新命名為 JavaScript。名字之所以變來變去,是當時網景與昇陽組成的開發聯盟,行銷策略原因只是為了讓這門語言搭上 Java 這個程式語言「熱詞」,才臨時改名為JavaScript,日後這也成為大眾對這門語言有諸多誤解的原因之一。(就像「狗和熱狗」,或「太陽和太陽餅」根本毫無關係,有沒有被騙了很久的感覺...)
早期網頁都是靜態顯示,為了讓網頁更加生動活潑,於是便誕生了 JavaScript。
JS 是一種程式語言,以純文件形式提供「腳本」(即程式內容)。腳本可以直接寫在 html 裡面,或在頁面引用外部連結,並在加載的時候自動執行。
現今的 JS 在瀏覽器、服務端或在有搭載任意 JS 引擎(或稱為「JS 虛擬機」)的設備中皆可執行。
JavaScript 引擎:
它就是理解並執行 JavaScript 程式碼的解釋器,有點像人對語言的處理。
目前市面上主要網頁瀏覽器的 JS 引擎整理如下:
JS 引擎代號 | 瀏覽器/執行環境 | 瀏覽器版本 | 說明 |
---|---|---|---|
V8 | Google Chrome | v1.0~v3.0 | 用C++編寫,開放原始碼 |
V8 | TrifleJS、Node.js...等 | ||
SpiderMonkey | Mozilla Firefox | 1.0~3.0 | 第一款JS引擎 |
TraceMonkey | Mozilla Firefox | 3.5~3.6 | 基於實時編譯的引擎,其中部份代碼取自Tamarin引擎 |
JaegerMonkey | Mozilla Firefox | 4.0以上 | 結合追踪和組合碼技術大幅提高性能,部分技術借鑿了V8、JavaScriptCore、WebKit |
Chakra (JScript引擎) | Microsoft Internet Explorer | 9 (32bit)、10、11 | 用C++編寫,開放原始碼 |
Chakra (JavaScript引擎) | Microsoft Edge | 用C++編寫,開放原始碼 | |
Rhino | HTMLUnit | 用Java編寫,開放原始碼 | |
JavaScriptCore | Apple Safari | 開放原始碼,用於webkit型瀏覽器 | |
Nitro | Apple Safari | 4 | JavaScriptCore 被改寫為SquirrelFish,升級版本為QuirrelFish Extreme,也叫做Nitro |
Linear A | Opera | 4.0~6.1 | |
Linear B | Opera | 7.0~9.2 | |
Futhark | Opera | 9.5~10.2 | |
Carakan | Opera | 10.50以上 | |
KJS,KDE的ECMAScript/JavaScript引擎 | Konqueror | 最初由哈里波頓開發,用於KDE專案瀏覽器 |
JavaScript 是當前網路上最流行,也是唯一被各家瀏覽器所共同支援的程式語言,同時亦是一種跨平台、輕量級、直譯式、物件導向、動態型別、弱型別的腳本語言。這門語言可用於 HTML 和 Web,更可廣泛用於伺服器、桌上型電腦、筆記本電腦、平板電腦和手機等設備。由於它不提供對內存或 CPU 的底層訪問,所以也被稱為一種安全的程式語言。
雖然作為獨立語言並不實用,但它可是為了能簡單嵌入其他產品和應用程式而設計。若寄宿在主體環境時,可以與環境中的物件相連,並以程式控制這些物件。雖然初期是用在網頁互動上,但它已不止局限在瀏覽器,也能應用在伺服端(如node.js)、手機app開發、遊戲開發、互動藝術等等。
JavaScript 是 1996 年創造的,於隔年 1997 年被網景公司提交給 Ecma 國際制定為標準。而 ECMAScript 簡稱 ES,是一種通用的程式語言,由 Ecma 國際在 ECMA-262 進行標準化。從 IE 3.0 開始,很多瀏覽器開始使用 ECMAScript。
所以簡單來說 ES 是 JS 的標準,目的是讓不同瀏覽器之間能根據 spec 版本來實作。類似市面上的電腦鍵盤,上面的字母、符號、方向鍵等,順序排列幾乎都是相同的位置,只是差在外型各有區別,這是因為各廠商皆遵守了相同的標準規範。而 JS 只是其中一種實作和擴充的程式語言,雖然 JS 相容於 ES 規範,但 JS 還提供 ES 未定義的特性。
當 ECMAScript 發布第三版(即 ES3)之後,便成為當時所有瀏覽器支援的程式語言,ES 後面的數字是版本號碼。從 2015 年起,改為以年份命名(如:ECMAScript 2015、ECMAScript 2016、ECMAScript 2017...),而因目前瀏覽器兼容性已漸漸提高,舊的瀏覽器也幾乎快被淘汰,因此最廣泛被使用的版本為改革幅度最大的 ES6 版。
儘管瀏覽器的 JS 引擎都能理解 JS,但有些瀏覽器的理解能力更強,對它的支持度亦不一樣。因此每當新的 ES 發布,JS 並沒有一次性支援所有新特性,這取決於引擎開發者是否有陸續開放新的支援。
ECMAScript Spec 版本演化表:
版本簡稱 | 版本官方名稱 | 說明 |
---|---|---|
ES1 | ECMAScript 1 (1997) | 第一版 |
ES2 | ECMAScript 2 (1998) | 編輯更改 |
ES3 | ECMAScript 3 (1999) | 新增「正規表達式」、try、catch、switch、do-while |
ES4 | ECMAScript 4 | 從未發布 |
ES5 | ECMAScript 5 (2009) | 支持 JSON、新增「嚴格模式」、String.trim()、Array.isArray()、數組迭代等方法、允許對象文字的尾隨逗號 |
ES6 | ECMAScript 2015 | 新增 let 和 const、默認參數值、Array.find()、Array.findIndex() |
ES7 | ECMAScript 2016 | 新增「指數運算符」、Array.includes() |
ES8 | ECMAScript 2017 | 新增「字串填充」、Object.entries()、Object.values()、異步函數、共享內存 |
ES9 | ECMAScript 2018 | 新增 rest、spread、異步迭代、Promise.finally()、在迴圈中使用await、更多「正規表達式」 |
ES10 | ECMAScript 2019 | 新的數據類型 BigInt,更友好的JSON.stringify、新增Array的flat()和flatMap()、String的trimStart()和trimEnd()、Object.fromEntries()、簡化try、catch,修改catch綁定...等 |
ES11 | ECMAScript 2020 | 新增 Promise.allSettled、可選鏈「?」、空值合併運算「??」、動態載入dynamic-import、globalThis |
ES12 | ECMAScript 2021 | 結合邏輯運算符和賦值表達式,新增「數字分隔符」、replaceAll、Promise.any、弱引用WeakRefs、Finalizers、FinalizationRegistry |
網頁的基礎語言架構為 HTML、CSS、JS。看下方圖表就知道了,他們各司其職卻又互相牽動,就像人體構造一樣,少一個都不行。
名稱 | 語言類別 | 負責項目 | 主要功能 |
---|---|---|---|
HTML | 標記語言 | 網頁「結構」(類似骨骼) | 網頁的「靜態」內容 |
CSS | 樣式規則語言 | 網頁「樣式」(類似皮膚外觀) | 「美化」網頁 |
JavaScript | 腳本語言 | 網頁「行為」(類似中樞神經) | 網頁的「動態」內容 |
瀏覽器中的 JS 可以做與網頁操作、用戶交互回應及 Web 伺服器相關的所有事情。
基於使用者的個資或訊息安全,在瀏覽器中的 JS 能力是受限的。目的是防止惡意網頁擷取用戶私人訊息或損害用戶數據。限制如下:
<input>
標籤選擇了硬碟中的文件等。網頁的加載性能,與瀏覽器的渲染機制關係密不可分,身為前端開發人員,必須先搞清楚瀏覽器背後的渲染機制,才能在開發中進行性能優化,所以我們就來了解一下瀏覽器是如何渲染頁面的吧:
首先是我們要讀取一個網站,必須先有它的網址(URL),然後在你的瀏覽器(如:Google Chrome)上打上這段長長的網址。
接著瀏覽器就會進行域名解析,並向服務器發起請求,並得到這個網址內的 HTML、CSS、images、JavaScript等。
然後你的瀏覽器在得到資料後,便會開始解析 html 並構建 DOM(DOM樹),且由上而下依序讀取顯示。
讀到 CSS 資料的時候,就會開始構建 CSSOM(CSS樹),並和 DOM 一起生成 Render Tree(渲染樹),計算出每個節點在螢幕中的位置,然後根據渲染樹對頁面進行渲染。
當讀到 JS 檔案時,網頁渲染會暫停,這時瀏覽器會先把 JS 腳本先執行完,再渲染後面的內容。所以 JS 腳本或檔案要放在 HTML 的最後 </body>
結束標籤之前,才不會導致頁面被中斷讀取過久而影響使用者體驗。(很重要,考試會考)
最後解譯器可以透過它的 JS 引擎幫我們編譯,並且即時顯示出效果,並透過顯卡把完整的頁面顯示到螢幕上,也就是我們打開網頁讀個幾秒後看到的樣子。
至於 DOM、CSSOM、渲染樹是什麼?裡面有相當多的專有名詞可以探討,但非本文要談論的重點。因為範圍有點太廣了,有興趣的可以到下面的參考資料補足你想知道的。
參考資料:
Q1:什麼是函數?什麼是函式?
A1:接下來本篇會教到一個新的名詞和用法,也就是 Function ,台灣翻譯叫「函數」、大陸翻譯「函式」,這裡我們統一以台灣版翻譯為主。
Q2:為何要使用函數(Function)?
A2:大部分的專案裡面都會存在著很多重複性的步驟,以 TodoList 來說:
今天上午新增一個 A、B、C 事項,然後下午修改了 B 事項,後來 A 事項被取消了,所以刪除。隔天在新增 D、E 事項,接著不久又修改 C、D 事項和刪除 E 事項。
(這時候就會看到工程師的經典表情...)
不論上述事項怎麼增增減減或修改,都還是依循著上一篇提到的5大主功能(儲存、顯示、新增、修改、刪除)在運作,只是把運作中的主角換掉。
如果用原先的程式碼來處理上述的工作,那工程師們可能都想撞牆了,因為都是一堆重複性的工作,無限的複製貼上,程式碼也不知道會爆出幾百幾千行,更別說超難維護與除錯的肥大檔案會造成網頁多大的負擔。既然重工在工程師們的眼裡是個毒瘤,那麼可以解救這些悲慘工程師來處理這些重複性的工作,就是非 Function(函數) 莫屬了。
函數是構成 javascript的基本要素之一。一個函數本身就是一段 JavaScript程式,包含用於執行某一個任務或計算的語法。要呼叫某一個函數之前,你必須先在這個函數想要執行的 scope 中定義它。
簡單來說:
就是把一段或多段的重複指令包起來,等到需要的時候呼叫它,以方便重複執行相同的任務。
所以本篇的學習重點,就是把上一篇的指令全部函數化之後,再呼叫執行而已。
這裡僅先以「函數宣告 Function Declaration」來使用和解說,若有興趣研究其他方法的同學請往這走,或是直接拉到文章最下方也有推薦參考文 ↓↓↓↓↓
函數宣告寫法:
function myFunction(){
.....
}
function 函數名稱 (參數1, 參數2, 參數3, ...) {
// 要執行的程式代碼
// 返回值 return
}
JS 白話文:
function
來宣告一個函數,後面加上自取的函數名稱(如:myFunction
、myName
...)。當然函數也可以沒有名稱,只是寫法不是這樣。沒有名字的函數在 JS 是合法的,通常我們稱它為「匿名函數」,這個暫時不是本文的討論範圍,以後等我()
中的內容,稱為參數(function parameters),多個參數則用逗號 ,
隔開。如果不需要參數,小括號內空白就好,但不可省略,例:function myName()
{}
內的內容,則是要執行的程式代碼,可用 return
這個功能,來返回指定的值給調用的參數,同時程式也會停止繼續執行,若不用 return
的話則會返回 undefined
。說了一堆聽不懂的,還是來個範例比較好理解。下方是早餐店漢堡的食譜,我們寫成函數試試看:
//牛肉漢堡
function HamburgerWithBeef(){
step1 = 'get one bread'; //第一步:放一片麵包
step2 = 'add Cheese'; //第二步:加起司
step3 = 'add Beef'; //第三步:牛肉放起來
step4 = 'put a pice of bread on top'; //第四步:再放一片麵包在上面
}
換成豬肉漢堡試試看:
//豬肉漢堡
function HamburgerWithPork(){
step1 = 'get one bread'; //第一步:放一片麵包
step2 = 'add Cheese'; //第二步:加起司
step3 = 'add Pork'; //第三步:豬肉放起來
step4 = 'put a pice of bread on top'; //第四步:再放一片麵包在上面
}
再換成雞肉漢堡:
//雞肉漢堡
function HamburgerWithChicken(){
step1 = 'get one bread'; //第一步:放一片麵包
step2 = 'add Cheese'; //第二步:加起司
step3 = 'add Chicken'; //第三步:雞肉放起來
step4 = 'put a pice of bread on top'; //第四步:再放一片麵包在上面
}
買尬!如果你是老闆,會不會覺得怎麼那麼煩,有夠多重複的工作方式,如果來個機器人員工幫忙製作就好了...
沒錯,函數就是來解決老闆們的煩惱,讓我們先找出哪裡不一樣!
看來似乎都是肉肉搞的鬼,這些要替換的肉類其實就是我們上面所講到的「參數(function parameters)」,但是參數要放在小括號裡面阿,所以我們稍微修改一下程式內容,把會變動的字改放到小括號內,我們取個參數名叫 meat
好了。
function HamburgerWith(meat){
step1 = 'get one bread'; //第一步:放一片麵包
step2 = 'add Cheese'; //第二步:加起司
step3 = 'add' + meat; //第三步:肉肉放起來
step4 = 'put a pice of bread on top'; //第四步:再放一片麵包在上面
}
宣告完啦!就這麼簡單幾句就可以完成製作各種漢堡的統一條件,但...這只是做完漢堡而已,都還沒到客人手中啊,這時就要用到 呼叫函數 來出餐了。
宣告完的函數並不會自動的執行,你必須呼叫函數,才會執行函數的內容。
寫法:
函數名稱(參數);
所以做完的漢堡出餐的執行方式就會是這樣...
HamburgerWith(Beef); //牛肉漢堡
HamburgerWith(Pork); //豬肉漢堡
HamburgerWith(Chicken); //雞肉漢堡
以上就是函數的概念,是不是簡單很多。
回到我們的 TodoList 專案,v2.0 版就是把上一篇寫的 code 全部函數化,以方便呼叫重複執行的指令。
先回憶一下上一版 v1.0 的 TodoList 長這樣:
// 1.儲存代辦清單內的陣列資料
var todos = ['item1','item2','item3'];
// 2.顯示代辦清單
console.log(todos);
// 3.新增新的項目
todos.push('newItem');
// 4.更改陣列內的值
todos[0] = 'updated';
// 5.刪除項目
todos.splice(2, 1);
1. 儲存代辦清單:
因為是宣告所有的代辦清單,所以這行不用動
2. 顯示代辦清單:
function showTodos() {
console.log('My todos: ', todos);
};
JS 白話文:
showTodos
,此項還用不到參數,所以小括號內容空白就好 ()
。console.log
的內容稍微美化一下,改放字串 'My todos: '
和變數名 todos
,主要是為了讓最後印出的資料看起來更好理解呼叫函數
showTodos();
();
保持空白3. 新增新的項目:
function addTodos(newTodos) {
myTodos.push(newTodos);
showTodos();
};
JS 白話文:
addTodos
,小括號內的參數先保持空白()
,等下再回頭處理它。myTodos.push('new item');
那行搬過來。小括號內 'new item'
是會隨著新增的名稱而任意變動,所以並不能以固定字串呈現,所以改為變數並取名為 newTodos
。(注意:變數名稱不可加上單引號或雙引號,否則又會變回字串。)function addTodos()
,小括號內的參數要填入剛剛的變數 newTodos
,這樣函數內外都有相同變數名稱,才能取值調用,並正確執行函數內容。showTodos();
來執行上面的程式。呼叫函數
addTodos('do my homework');
'do my homework'
'do my homework'
4. 更改陣列內的值:
function changeTodo (position, updatedName) {
todos[position] = updatedName;
showTodos();
};
JS 白話文:
function
後的小括號內 2個參數,都要改為變數,參數1(修改位置)取名為 position
。參數2(修改後的名稱)取名為 updatedName
。todos[0] = 'updated';
那行搬過來。中括號 [0]
內指的是修改位置,和上方的參數1 position
相同,接著 =
右方是修改後名稱,也和上方參數2 updatedName
相同,這樣才可正確的取到值並調用修改原有的清單項目內容。showTodos();
執行程式。呼叫函數
changeTodo(1, 'take a rest');
'item2'
),參數二是修改後名稱,如 'take a rest.'
。console.log
則印出 My todos: ['item1','take a rest','item3', 'do my homework'],可以發現第二項的 'item2'
已經被修改為 'take a rest'
5. 刪除項目:
function deleteTodo(position) {
todos.splice(position, 1);
showTodos();
};
先回憶一下Array的刪除指令用法 .splice(index, howmany, item1, ....., itemX)
,小括號內包含了:
1.第一個參數 index(必填):指定新增或刪除的序列號碼
2.第二個參數 howmany(選填):從指定新增或刪除的位置起算,共要移除幾筆資料
3.第三個參數 item1,.....,itemX(選填):為新增或修改後的內容(字串要加上單或雙引號),這裡不需要所以不填
JS 白話文:
function
的小括號 ()
,只需要第一個參數值,也就是變數 position
,因為沒有要修改或異動項目名稱,當然也就不需要參數2,position
的值,在使用刪除指令時, .splice()
的第 1個參數,就填入這個變數 position
,而不是清單項目的位置。showTodos();
執行程式。呼叫函數
deleteTodo(0);
console.log
則印出 My todos: ['take a rest','item3', 'do my homework'] ,可以發現第一項的 'item1'
已經不見了。終於結束了鬼打牆的程式解說,一樣幫各位統整一下剛剛 v2.0 的程式碼
// 1.儲存代辦清單內的陣列資料
var todos = ['item1','item2','item3'];
// 2.顯示代辦清單
function showTodos() {
console.log('My todos: ', todos);
};
// 3.新增新的項目
function addTodos(newTodos) {
myTodos.push(newTodos);
showTodos();
};
// 4.更改陣列內的值
function changeTodo (position, updatedName) {
todos[position] = updatedName;
showTodos();
};
// 5.刪除項目
function deleteTodo(position) {
todos.splice(position, 1);
showTodos();
};
這篇我們學習到具名函數的結構和表達方式,以及如何取值調用。不過這裡只是函數領域的冰山一角,它還有很多更細節的領域可以去探索。本文僅提供施作 ToDoList 專案的功能代碼介紹而已,不多詳加贅述關於函數的其他功能,如果你有興趣,可以看下方的參考資料,或是多去爬文了解,也許可以更帶領你增進許多關於函數的知識。
本文學習參考資料:
]]>Q1:什麼是函數?什麼是函式?
A1:接下來本篇會教到一個新的名詞和用法,也就是 Function ,台灣翻譯叫「函數」、大陸翻譯「函式」,這裡我們統一以台灣版翻譯為主。
Q2:為何要使用函數(Function)?
A2:大部分的專案裡面都會存在著很多重複性的步驟,以 TodoList 來說:
今天上午新增一個 A、B、C 事項,然後下午修改了 B 事項,後來 A 事項被取消了,所以刪除。隔天在新增 D、E 事項,接著不久又修改 C、D 事項和刪除 E 事項。
(這時候就會看到工程師的經典表情...)
不論上述事項怎麼增增減減或修改,都還是依循著上一篇提到的5大主功能(儲存、顯示、新增、修改、刪除)在運作,只是把運作中的主角換掉。
如果用原先的程式碼來處理上述的工作,那工程師們可能都想撞牆了,因為都是一堆重複性的工作,無限的複製貼上,程式碼也不知道會爆出幾百幾千行,更別說超難維護與除錯的肥大檔案會造成網頁多大的負擔。既然重工在工程師們的眼裡是個毒瘤,那麼可以解救這些悲慘工程師來處理這些重複性的工作,就是非 Function(函數) 莫屬了。
函數是構成 javascript的基本要素之一。一個函數本身就是一段 JavaScript程式,包含用於執行某一個任務或計算的語法。要呼叫某一個函數之前,你必須先在這個函數想要執行的 scope 中定義它。
簡單來說:
就是把一段或多段的重複指令包起來,等到需要的時候呼叫它,以方便重複執行相同的任務。
所以本篇的學習重點,就是把上一篇的指令全部函數化之後,再呼叫執行而已。
這裡僅先以「函數宣告 Function Declaration」來使用和解說,若有興趣研究其他方法的同學請往這走,或是直接拉到文章最下方也有推薦參考文 ↓↓↓↓↓
函數宣告寫法:
function myFunction(){
.....
}
function 函數名稱 (參數1, 參數2, 參數3, ...) {
// 要執行的程式代碼
// 返回值 return
}
JS 白話文:
function
來宣告一個函數,後面加上自取的函數名稱(如:myFunction
、myName
...)。當然函數也可以沒有名稱,只是寫法不是這樣。沒有名字的函數在 JS 是合法的,通常我們稱它為「匿名函數」,這個暫時不是本文的討論範圍,以後等我()
中的內容,稱為參數(function parameters),多個參數則用逗號 ,
隔開。如果不需要參數,小括號內空白就好,但不可省略,例:function myName()
{}
內的內容,則是要執行的程式代碼,可用 return
這個功能,來返回指定的值給調用的參數,同時程式也會停止繼續執行,若不用 return
的話則會返回 undefined
。說了一堆聽不懂的,還是來個範例比較好理解。下方是早餐店漢堡的食譜,我們寫成函數試試看:
//牛肉漢堡
function HamburgerWithBeef(){
step1 = 'get one bread'; //第一步:放一片麵包
step2 = 'add Cheese'; //第二步:加起司
step3 = 'add Beef'; //第三步:牛肉放起來
step4 = 'put a pice of bread on top'; //第四步:再放一片麵包在上面
}
換成豬肉漢堡試試看:
//豬肉漢堡
function HamburgerWithPork(){
step1 = 'get one bread'; //第一步:放一片麵包
step2 = 'add Cheese'; //第二步:加起司
step3 = 'add Pork'; //第三步:豬肉放起來
step4 = 'put a pice of bread on top'; //第四步:再放一片麵包在上面
}
再換成雞肉漢堡:
//雞肉漢堡
function HamburgerWithChicken(){
step1 = 'get one bread'; //第一步:放一片麵包
step2 = 'add Cheese'; //第二步:加起司
step3 = 'add Chicken'; //第三步:雞肉放起來
step4 = 'put a pice of bread on top'; //第四步:再放一片麵包在上面
}
買尬!如果你是老闆,會不會覺得怎麼那麼煩,有夠多重複的工作方式,如果來個機器人員工幫忙製作就好了...
沒錯,函數就是來解決老闆們的煩惱,讓我們先找出哪裡不一樣!
看來似乎都是肉肉搞的鬼,這些要替換的肉類其實就是我們上面所講到的「參數(function parameters)」,但是參數要放在小括號裡面阿,所以我們稍微修改一下程式內容,把會變動的字改放到小括號內,我們取個參數名叫 meat
好了。
function HamburgerWith(meat){
step1 = 'get one bread'; //第一步:放一片麵包
step2 = 'add Cheese'; //第二步:加起司
step3 = 'add' + meat; //第三步:肉肉放起來
step4 = 'put a pice of bread on top'; //第四步:再放一片麵包在上面
}
宣告完啦!就這麼簡單幾句就可以完成製作各種漢堡的統一條件,但...這只是做完漢堡而已,都還沒到客人手中啊,這時就要用到 呼叫函數 來出餐了。
宣告完的函數並不會自動的執行,你必須呼叫函數,才會執行函數的內容。
寫法:
函數名稱(參數);
所以做完的漢堡出餐的執行方式就會是這樣...
HamburgerWith(Beef); //牛肉漢堡
HamburgerWith(Pork); //豬肉漢堡
HamburgerWith(Chicken); //雞肉漢堡
以上就是函數的概念,是不是簡單很多。
回到我們的 TodoList 專案,v2.0 版就是把上一篇寫的 code 全部函數化,以方便呼叫重複執行的指令。
先回憶一下上一版 v1.0 的 TodoList 長這樣:
// 1.儲存代辦清單內的陣列資料
var todos = ['item1','item2','item3'];
// 2.顯示代辦清單
console.log(todos);
// 3.新增新的項目
todos.push('newItem');
// 4.更改陣列內的值
todos[0] = 'updated';
// 5.刪除項目
todos.splice(2, 1);
1. 儲存代辦清單:
因為是宣告所有的代辦清單,所以這行不用動
2. 顯示代辦清單:
function showTodos() {
console.log('My todos: ', todos);
};
JS 白話文:
showTodos
,此項還用不到參數,所以小括號內容空白就好 ()
。console.log
的內容稍微美化一下,改放字串 'My todos: '
和變數名 todos
,主要是為了讓最後印出的資料看起來更好理解呼叫函數
showTodos();
();
保持空白3. 新增新的項目:
function addTodos(newTodos) {
myTodos.push(newTodos);
showTodos();
};
JS 白話文:
addTodos
,小括號內的參數先保持空白()
,等下再回頭處理它。myTodos.push('new item');
那行搬過來。小括號內 'new item'
是會隨著新增的名稱而任意變動,所以並不能以固定字串呈現,所以改為變數並取名為 newTodos
。(注意:變數名稱不可加上單引號或雙引號,否則又會變回字串。)function addTodos()
,小括號內的參數要填入剛剛的變數 newTodos
,這樣函數內外都有相同變數名稱,才能取值調用,並正確執行函數內容。showTodos();
來執行上面的程式。呼叫函數
addTodos('do my homework');
'do my homework'
'do my homework'
4. 更改陣列內的值:
function changeTodo (position, updatedName) {
todos[position] = updatedName;
showTodos();
};
JS 白話文:
function
後的小括號內 2個參數,都要改為變數,參數1(修改位置)取名為 position
。參數2(修改後的名稱)取名為 updatedName
。todos[0] = 'updated';
那行搬過來。中括號 [0]
內指的是修改位置,和上方的參數1 position
相同,接著 =
右方是修改後名稱,也和上方參數2 updatedName
相同,這樣才可正確的取到值並調用修改原有的清單項目內容。showTodos();
執行程式。呼叫函數
changeTodo(1, 'take a rest');
'item2'
),參數二是修改後名稱,如 'take a rest.'
。console.log
則印出 My todos: ['item1','take a rest','item3', 'do my homework'],可以發現第二項的 'item2'
已經被修改為 'take a rest'
5. 刪除項目:
function deleteTodo(position) {
todos.splice(position, 1);
showTodos();
};
先回憶一下Array的刪除指令用法 .splice(index, howmany, item1, ....., itemX)
,小括號內包含了:
1.第一個參數 index(必填):指定新增或刪除的序列號碼
2.第二個參數 howmany(選填):從指定新增或刪除的位置起算,共要移除幾筆資料
3.第三個參數 item1,.....,itemX(選填):為新增或修改後的內容(字串要加上單或雙引號),這裡不需要所以不填
JS 白話文:
function
的小括號 ()
,只需要第一個參數值,也就是變數 position
,因為沒有要修改或異動項目名稱,當然也就不需要參數2,position
的值,在使用刪除指令時, .splice()
的第 1個參數,就填入這個變數 position
,而不是清單項目的位置。showTodos();
執行程式。呼叫函數
deleteTodo(0);
console.log
則印出 My todos: ['take a rest','item3', 'do my homework'] ,可以發現第一項的 'item1'
已經不見了。終於結束了鬼打牆的程式解說,一樣幫各位統整一下剛剛 v2.0 的程式碼
// 1.儲存代辦清單內的陣列資料
var todos = ['item1','item2','item3'];
// 2.顯示代辦清單
function showTodos() {
console.log('My todos: ', todos);
};
// 3.新增新的項目
function addTodos(newTodos) {
myTodos.push(newTodos);
showTodos();
};
// 4.更改陣列內的值
function changeTodo (position, updatedName) {
todos[position] = updatedName;
showTodos();
};
// 5.刪除項目
function deleteTodo(position) {
todos.splice(position, 1);
showTodos();
};
這篇我們學習到具名函數的結構和表達方式,以及如何取值調用。不過這裡只是函數領域的冰山一角,它還有很多更細節的領域可以去探索。本文僅提供施作 ToDoList 專案的功能代碼介紹而已,不多詳加贅述關於函數的其他功能,如果你有興趣,可以看下方的參考資料,或是多去爬文了解,也許可以更帶領你增進許多關於函數的知識。
本文學習參考資料:
]]>所學知識早已跟不上日新月異的網頁技術,便研究了一下 JQ 和 JS,原來 JQ 是以 JS 去編寫的函式庫,所以概念運用其實很相近,且 JQ 的語法親民很多,還有很多網路大神貢獻的諸多效果範本可運用,對沒什麼程式基礎的網頁美術設計師而言,真心就是個救世主來著。只是網頁需要用到的,不僅僅動態效果要處理,還有很多介面或表單上的互動和資料傳遞,單靠 JQ 的處理是不夠的,最好的學習方式,就是從它的原生語言 javaScript 著手。
在研讀了Adam Lin老師「JavaScript基礎入門」,還有Danny Huang老師「JavaScript新手秘笈|三大專案帶你輕鬆入門」,及六角學院「JavaScript 入門篇 - 學徒的試煉」 的課程之後,真心覺得沒有實作和學習筆記輔助,就會導致今天學習明天忘記的窘狀。於是拋掉無聊的自尊心,提筆了我荒廢XX年的寫作技術,由號稱程式基本款的 To do list 的介面互動開始!
在開始做 TodoList 這個小專案之前,首先我們可能需要稍微學習一下關於 javaScript 的一些程式語法架構,這時候就推薦使用 JS 的官方文件或是最著名的 w3schools 來做程式碼的輔助查詢,或是研讀上方提供的 JS 學習課程亦可(不過不是免費的喔~)。
由於本人是 JS 初心者,所以照著老師教學的要求,一開始教的程式碼都不會很艱深,後面慢慢會有好多版來強化這5個功能的使用,目前預計會有約11版的使用者故事。
TodoList v1.0 實作開始:
JS 儲存資料的方式,就不能不提 變數(Variable) 了!所有不同項目的代辦事項都是資料對吧,必須有地方儲存它,才能在日後讀取出來,或是對它做其他功能使用,如編輯、刪除等,而這個存放的盒子就稱之為變數。
變數可使用 var 來宣告才能對它做後續指令的下達,但因儲存的代辦事項不可能只有一項(總不會永遠都只有一件事要做吧?!!),所以還需要運用到 陣列(Array) 來儲存各個代辦事項。
寫法:var 變數名稱 = [XXX, OOO, ZZZ];
(中括號內 XXX, OOO, ZZZ 就是你要新增的內容)
//儲存代辦清單內的陣列資料
var myTodos = ['item1','item2','item3'];
js 白話文:
使用 console.log 這個指令來印出陣列中的內容。
寫法:console.log(變數名稱);
(中括號內填上你之前宣告的變數名稱)
//顯示代辦清單
console.log(myTodos);
js 白話文:
因為這個專案是用 陣列(Array) 在存取資料,所以包含新增、更新、刪除等功能,都要從 Array 去尋找這些功能指令。這裡可使用 push 指令,增加新建的代辦項目,而增加的內容會出現在陣列內的最後面,接著再用 console.log 印出結果看看。
寫法:變數名稱 .push(aaa);
(小括號內就是你要新增的資料,aaa是我亂填的,可填任意數字或字串。)
//新增新的項目
myTodos.push('new item');
console.log(myTodos);
js 白話文:
在講更新這個功能之前,必須先知道陣列內容的序列號碼排序方式。我們幼稚園學過數數字都是從 1開始疊加計算,而 JavaScript 卻是從 0 開始起算,不是從 1 開始!因此我們要取出陣列的值的話,第一個值的序列號碼就是 0,第二個是 1,第三個是 2...依此類推。看不懂的話,直接來看範例比較清楚:
var youtuber = ['老高與小茉', '蔡阿嘎', '反正我很閒', 'Joeman', '這群人'];
console.log(youtuber[0]);
js 白話文:
知道陣列序列號碼的排序之後,回到 TodoList 專案,用以下方法來取值:
todos[0];
//可以取到第 1個值 item1
todos[1];
//可以取到第 2個值 item2
todos[3];
//可以取到第 3個值 item3
更改陣列值的方式很簡單,就是在取值後方加上等號「=」和新的內容(字串一樣要加上單或雙引號)。
//更改陣列內的值
todos[0] = 'updatedName';
console.log(todos);
js 白話文:
再來要運用到 Array 的 Splice 的功能了,它可以刪除原有的資料,或新增修改陣列中的內容。來個範例比較好解釋:
寫法:arrayObject.splice(index, howmany, item1, ....., itemX)
小括號內包含了三個參數。
//刪除項目
todos.splice(2, 1);
console.log(todos);
js 白話文:好啦就這麼簡單!幫各位統整一下剛剛專案需要的程式碼,才不會混了其他範例而感到混亂。
//1.儲存代辦清單內的陣列資料
var todos = ['item1','item2','item3'];
//2.顯示代辦清單
console.log(todos);
//3.新增新的項目
todos.push('newItem');
//4.更改陣列內的值
todos[0] = 'updated';
//5.刪除項目
todos.splice(2, 1);
在這篇我們學習到 Var(宣告)、變數、array(陣列)、console.log(顯示或印出)、push(陣列新增)、陣列修改、splice(陣列刪除或異動)等指令寫法,是不是沒有想像中那麼複雜。當然事實上不是這樣就解決了,這只是最基礎的寫法,再來會有後續文章詳解,就像洋蔥一樣,一層一層的把細部功能和邏輯運算加上去,最終就是我們要的結果了!
之前學習到的方式,大多都是指令的名詞解釋,對新手而言,有點像學了abc,然後才開始教片語和文法跟文章。雖然方法沒有錯,但是老實說很沒效率。對新手而言,吸收度實在超級不佳,不論看了幾個教學影片,都很容易深深的進入冬眠階段(應該不是只有我吧...)。當然學習力不佳不外乎是自己專注力的問題,或是老師的教學方式、說話節奏、語調,還有很多老師可怕的大頭照總喜歡貼在角落吸走學習的目光 XD。
我的學習體驗感受是,從實作開始學習,再拆解每個步驟指令和邏輯用法會比較容易理解。就是因為容易解構錯誤,所以能從錯誤和不解中找到問題所在,加深編寫程式和查找資料的能力。還可以讓人打起精神去找問題,而非像以前學生時代上課,一聽老師講課就想睡覺的地獄輪迴,重點不是你在做阿,你只是聽而已。跟先把完全不會講英文的你丟到國外,幾個月或幾年後,你也會講的比外語系大學生還流利和道地的學習方法是一樣的。
本文學習參考資料:
]]>所學知識早已跟不上日新月異的網頁技術,便研究了一下 JQ 和 JS,原來 JQ 是以 JS 去編寫的函式庫,所以概念運用其實很相近,且 JQ 的語法親民很多,還有很多網路大神貢獻的諸多效果範本可運用,對沒什麼程式基礎的網頁美術設計師而言,真心就是個救世主來著。只是網頁需要用到的,不僅僅動態效果要處理,還有很多介面或表單上的互動和資料傳遞,單靠 JQ 的處理是不夠的,最好的學習方式,就是從它的原生語言 javaScript 著手。
在研讀了Adam Lin老師「JavaScript基礎入門」,還有Danny Huang老師「JavaScript新手秘笈|三大專案帶你輕鬆入門」,及六角學院「JavaScript 入門篇 - 學徒的試煉」 的課程之後,真心覺得沒有實作和學習筆記輔助,就會導致今天學習明天忘記的窘狀。於是拋掉無聊的自尊心,提筆了我荒廢XX年的寫作技術,由號稱程式基本款的 To do list 的介面互動開始!
在開始做 TodoList 這個小專案之前,首先我們可能需要稍微學習一下關於 javaScript 的一些程式語法架構,這時候就推薦使用 JS 的官方文件或是最著名的 w3schools 來做程式碼的輔助查詢,或是研讀上方提供的 JS 學習課程亦可(不過不是免費的喔~)。
由於本人是 JS 初心者,所以照著老師教學的要求,一開始教的程式碼都不會很艱深,後面慢慢會有好多版來強化這5個功能的使用,目前預計會有約11版的使用者故事。
TodoList v1.0 實作開始:
JS 儲存資料的方式,就不能不提 變數(Variable) 了!所有不同項目的代辦事項都是資料對吧,必須有地方儲存它,才能在日後讀取出來,或是對它做其他功能使用,如編輯、刪除等,而這個存放的盒子就稱之為變數。
變數可使用 var 來宣告才能對它做後續指令的下達,但因儲存的代辦事項不可能只有一項(總不會永遠都只有一件事要做吧?!!),所以還需要運用到 陣列(Array) 來儲存各個代辦事項。
寫法:var 變數名稱 = [XXX, OOO, ZZZ];
(中括號內 XXX, OOO, ZZZ 就是你要新增的內容)
//儲存代辦清單內的陣列資料
var myTodos = ['item1','item2','item3'];
js 白話文:
使用 console.log 這個指令來印出陣列中的內容。
寫法:console.log(變數名稱);
(中括號內填上你之前宣告的變數名稱)
//顯示代辦清單
console.log(myTodos);
js 白話文:
因為這個專案是用 陣列(Array) 在存取資料,所以包含新增、更新、刪除等功能,都要從 Array 去尋找這些功能指令。這裡可使用 push 指令,增加新建的代辦項目,而增加的內容會出現在陣列內的最後面,接著再用 console.log 印出結果看看。
寫法:變數名稱 .push(aaa);
(小括號內就是你要新增的資料,aaa是我亂填的,可填任意數字或字串。)
//新增新的項目
myTodos.push('new item');
console.log(myTodos);
js 白話文:
在講更新這個功能之前,必須先知道陣列內容的序列號碼排序方式。我們幼稚園學過數數字都是從 1開始疊加計算,而 JavaScript 卻是從 0 開始起算,不是從 1 開始!因此我們要取出陣列的值的話,第一個值的序列號碼就是 0,第二個是 1,第三個是 2...依此類推。看不懂的話,直接來看範例比較清楚:
var youtuber = ['老高與小茉', '蔡阿嘎', '反正我很閒', 'Joeman', '這群人'];
console.log(youtuber[0]);
js 白話文:
知道陣列序列號碼的排序之後,回到 TodoList 專案,用以下方法來取值:
todos[0];
//可以取到第 1個值 item1
todos[1];
//可以取到第 2個值 item2
todos[3];
//可以取到第 3個值 item3
更改陣列值的方式很簡單,就是在取值後方加上等號「=」和新的內容(字串一樣要加上單或雙引號)。
//更改陣列內的值
todos[0] = 'updatedName';
console.log(todos);
js 白話文:
再來要運用到 Array 的 Splice 的功能了,它可以刪除原有的資料,或新增修改陣列中的內容。來個範例比較好解釋:
寫法:arrayObject.splice(index, howmany, item1, ....., itemX)
小括號內包含了三個參數。
//刪除項目
todos.splice(2, 1);
console.log(todos);
js 白話文:好啦就這麼簡單!幫各位統整一下剛剛專案需要的程式碼,才不會混了其他範例而感到混亂。
//1.儲存代辦清單內的陣列資料
var todos = ['item1','item2','item3'];
//2.顯示代辦清單
console.log(todos);
//3.新增新的項目
todos.push('newItem');
//4.更改陣列內的值
todos[0] = 'updated';
//5.刪除項目
todos.splice(2, 1);
在這篇我們學習到 Var(宣告)、變數、array(陣列)、console.log(顯示或印出)、push(陣列新增)、陣列修改、splice(陣列刪除或異動)等指令寫法,是不是沒有想像中那麼複雜。當然事實上不是這樣就解決了,這只是最基礎的寫法,再來會有後續文章詳解,就像洋蔥一樣,一層一層的把細部功能和邏輯運算加上去,最終就是我們要的結果了!
之前學習到的方式,大多都是指令的名詞解釋,對新手而言,有點像學了abc,然後才開始教片語和文法跟文章。雖然方法沒有錯,但是老實說很沒效率。對新手而言,吸收度實在超級不佳,不論看了幾個教學影片,都很容易深深的進入冬眠階段(應該不是只有我吧...)。當然學習力不佳不外乎是自己專注力的問題,或是老師的教學方式、說話節奏、語調,還有很多老師可怕的大頭照總喜歡貼在角落吸走學習的目光 XD。
我的學習體驗感受是,從實作開始學習,再拆解每個步驟指令和邏輯用法會比較容易理解。就是因為容易解構錯誤,所以能從錯誤和不解中找到問題所在,加深編寫程式和查找資料的能力。還可以讓人打起精神去找問題,而非像以前學生時代上課,一聽老師講課就想睡覺的地獄輪迴,重點不是你在做阿,你只是聽而已。跟先把完全不會講英文的你丟到國外,幾個月或幾年後,你也會講的比外語系大學生還流利和道地的學習方法是一樣的。
本文學習參考資料:
]]>