本文主要內容為程式設計簡介,在此可看到在初學階段所必須理解的各種專有名詞。
以下一一仔細跟大家說明 ( ゚∀゚)o彡
程式(program)又稱原始碼(source code)、程式碼(code),用來表示一群執行特定工作的指令,也可說是述句組成的集合。
規範有效指令與組合的規則,稱為電腦語言(computer language)或語法(syntax)。
可想成若希望能編寫電腦可懂的語言,就必須遵循一套規則來撰寫,而這個規則就是語法,就和我們平常溝通所說的語言的文法是一樣的。
會執行特定工作的字詞、數字或運算子(operator)組合,即是述句(statement),例如:a = b + 1
就會執行 b + 1
並將結果指定給 a。
獨立存在的值,沒有存在於任何變數中,例如:a = b + 1
中的 1。
直譯器與編譯器可將程式碼由上到下逐行轉為電腦可懂的命令。
其差別在於時機點
對變數或值進行操作的字元,例如:a = b + 1
中的 =
和 +
。
JavaScript 有以下幾種運算子。
=
)來進行「指定」的工作,當計算完畢等號右邊的值後,接著將結果放進等號左邊的變數,這個放進去的動作就是指定。例如:a = b + 1
,就是將 b + 1
的結果放到 a。+
)減(-
)乘(*
)除(/
)的運算,例如:b + 1
。+=
、-=
、*=
和 /=
,將算術運算子和指定運算子結合在一起,例如:a += 1
,等同於 a = a + 1
。++
(遞增)與 --
(遞減),例如 a++
,等同於 a = a + 1
。.
(點記號法,dot notation) 或 [ ]
(方括號記號法,bracket notation) 的方式存取物件的特性,例如:obj.a
或 obj['a']
,.
因為簡單便利較常使用,但 [ ]
卻可在索引值是變數或有特殊字元時能保證完成值的存取,例如:obj['h e l l o']
(有空白)、obj['#$%^&']
(特殊字元)、obj['123']
(開頭為數字)。若想了解命名規則,待變數命名的部份會再詳述。==
(寬鬆相等)、===
(嚴格相等)、!=
(寬鬆不相等)、!==
(嚴格不相等),主要差異是在做值的比較時是否會做強制轉型,待下文相等性的部份再做解釋和舉例。<
(小於)、 >
(大於)、<=
(小於等於)、>=
(大於等於),例如:a > b
表示比較 a 是否大於 b。注意,比較的結果一定會是布林值,待下文不等性的部份再做解釋和舉例。&&
(and)、||
(or),例如:a || b
表示選擇 a 或 b,常用於表達複合條件、設定初始值。5 & 1
會被看成 0101 & 0001
,得到結果 0001,回傳 1 。點此看更多範例。5 & 1 // 1
+
可串接兩字元,並回傳結果,通常用於連接變數與字串。不過目前都改用 ES6 的字串模板(string template)了,使用 ${ variable_name }
即可代入變數,而不需再用 +
與雙/單引號拼湊字串,方便許多,範例如下。const name = 'Summer';
// 使用字串運算子
const greetings_1 = 'Hello ' + name + '!'; // "Hello Summer!"
// 使用字串模板
const greetings_2 = `Hello ${name}!`; // "Hello Summer!"
條件 ? 值1 : 值2
。若「條件」為 true,運算子回傳「值1」,否則回傳「值2」。如下,條件 count <= 0
得到 false,因此得到 prompt 為「還有存貨」。const count = 10;
const prompt = count <= 0 ? '全部賣完了' : '還有存貨';
prompt // "還有存貨"
,
用來隔開多個運算式並由左至右循序執行,最後會回傳最右邊的運算式的結果,通常用於 (1) for 迴圈內部,讓多個變數能在每次迴圈中被更新;(2) 變數宣告。for(let i = 0, j = 10; i < j; i++, j--) {
console.log(`i: ${i}, j: ${j}`);
}
// i: 0, j: 10
// i: 1, j: 9
// i: 2, j: 8
// i: 3, j: 7
// i: 4, j: 6
const x = 1;
y = 2;
const product = {
name: 'apple',
count: 100,
}
delete x // false
x // 1
delete y // true
y // Uncaught ReferenceError: y is not defined
delete product.count // true
product // {name: "apple"}
in 運算子的範例。
const product = {
name: 'apple',
count: 100,
}
'name' in product // true
'valid' in product // false
instanceof 運算子的範例。
product instanceof Object // true
product instanceof Array // false
對「某個變數或值,或以運算子結合起來的一組變數或值」的參考(reference)。例如:a = b + 1
這個述句中有四個運算式,分別是 1、b、b + 1
、a = b + 1
,其中 1 是字面值運算式(literal value expression)、b 是變數運算式(variable expression)用來取得變數的值、b + 1
是算術運算式(arithmetic expression)用來進行加法運算、a = b + 1
是指定運算式(assignment expression)用來將結果指定給變數存起來。這裡順道一提「呼叫運算式(call expression)」,意即函式呼叫運算式本身,例如:alert(a)
。
題外話,曾幾何時我以為當工程師超酷炫的,應該都像 Daisy Johnson 一樣這麼殺吧。
當年 Daisy Johnson 只是個駭客不打壞人只打電腦時就已經這麼迷人了 (๑╹◡╹๑)
圖片來源:5 reasons why Skye from ‘Agents of S.H.I.E.L.D.’ is a Mary Sue and why it hurts the show
好了好了,夢醒了,趕快繼續幹活 (  ̄ 3 ̄)y▂ξ
型別,指的是「值的不同的表示法」,主要分為兩種「基本型別」(primitives,即 number、string、boolean、null、undefined、symbol)和「物件型別」(object)。
'Hello World'
。除了基本型別外的資料型別都是物件,物件型別又分以下子型別
function sayHi(name) {
console.log(`Hi, I am ${name}`);
}
sayHi('Jack'); // Hi, I am Jack
我們有時候會需要將資料在不同型別間轉換,例如,遇到在表單中輸入一連串的金額(此時是字串),接著計算總金額時就會希望將這些字串轉成數字來做加減乘除的操作,這時候就可能需要做轉型,從字串轉成數字。
例如,小明在蝦 X 買了一件商品準備在母親節送給媽媽,並選擇貨到付款。
圖片來源:母親節送地方媽媽小黃瓜「煮菜啦!」
來看看商品金額、運費和總金額,商品金額(product)是 100(以字串型態存在),運費(shipment)也同樣是 100(以數字型態存在),這時候總金額 total 是?
const product = '100';
const shipment = 100;
咦?怎麼會是 100100!
const total = product + shipment; // 100100
原來是因為若兩值資料型別不同,當其中一方是字串時,+
所代表的就是字串運算子,而將數字強制轉型為字串,並連接兩個字串。解法就是使用 Number 強制轉型(coerce),將字串的部份轉為數字就可以做數學運算了。
const product = '100';
const shipment = 100;
const total = Number(product) + shipment; // 200
又,除了強制轉型,來看在比較兩個非相同型別的值的時候會發生隱含的(implicit)轉型。
例如,小明想要比較買這個商品付這個運費划算嗎?運費該不會比商品還貴吧?
product === shipment // false
product == shipment // true
咦?一個是字串、一個是數字,是怎麼能做比較?這是由於 JavaScript 偷偷做了(隱含的)轉型的原因。那...到底做了什麼呢?
product === shipment
:不做轉型,因此型別對比較是有影響的。product == shipment
:會強制轉型,規則是 (1) 布林轉數字;(2) 字串轉數字;(3) 使用 valueOf()
將物件取得基本型別的值,再做比較。關於強制轉型的詳細說明,之後會再詳述,或參考規格。小明看到商品價格與運費居然相等,還是先湊個免運再買吧!
typeof 可用於檢測值的型別是什麼。
typeof 'Hello World!' // 'string'
typeof true // 'boolean'
typeof 1234567 // 'number'
typeof null // 'object'
typeof undefined // 'undefined'
typeof { name: 'Jack' } // 'object'
typeof Symbol() // 'symbol'
typeof function() {} // 'function'
typeof [1, 2, 3] // 'object'
typeof NaN // 'number'
這裡會看到幾個有趣的(奇怪的)地方...
typeof null
卻得到 object,而非 null!這可說是一個 bug,可是若因為修正了這個 bug 則可能會導致很多網站壞掉,因此就不修了!typeof function() {}
是得到 function 而非 object,和陣列依舊得到 object 是不一樣的。typeof NaN
結果就是 number,不要被字面上的意思「不是數字」(not a number)給弄糊塗了。另外,NaN 與任何數字運算都會得到 NaN,並且 NaN 不大於、不小於也不等於任何數字,包含 NaN 它自己。看到這裡是不是覺得 JavaScript 很難懂呢? (/‵Д′)/~ ╧╧
意即物件以屬性(或稱方法)的形式對外提供的行為,例如
const prompt = 'Hello World';
prompt.length // 11
這背後的原因是每個型別基本上都會有其物件包裹器(object wrapper,又稱原生 natives)的型態做對應使用,例如資料型別 string 的物件包裹器型態就是 String,而就是這個包裹器型態在其原型(prototype)上定義了許多屬性和方法,因此這些資料型態就能如物件般擁有屬性和方法以供使用。
關於相等性的運算子有四個「==
」(寬鬆相等性 loose equality)、「===
」(嚴格相等性 strict equality)、「!=
」和「!==
」。寬鬆與嚴格的差異在於檢查值相等時,是否會做強制轉型,==
會做強制轉型,而 ===
不會。
const a = '100';
const b = 100;
a == b // true,強制轉型,將字串 '100' 轉為數字 100
a === b // false
另外,關於值的儲存方式有傳值「pass by value」和傳址/參考「pass by referece」兩種,其中 pass by value 又可再細分是否為「pass by sharing」(可參考這篇),基本型別是傳值,而物件型別是傳址。當比較兩物件時,比較的是儲存的位置,因此看起來是相同的物件,但比較結果卻是不相同的。
const a = [1, 2, 3, 4, 5];
const b = [1, 2, 3, 4, 5];
a == b // false
關於不等性的比較運算子有 >
、<
、>=
、<=
共四種,在這裡有幾種狀況需要注意
'ab' < 'cd' // true
'99' > 98 // true,字串 '99' 被強制轉型為數字 99
'Hello World' > 1 // false,字串 'Hello World' 無法轉為數字,變成 NaN
'Hello World' < 1 // false
'Hello World' = 1 // false
NaN > NaN // false
NaN < NaN // false
NaN === NaN // false
NaN == NaN // false
看到這裡如果覺得 JavaScript 很難學,莫慌莫急莫害怕,推薦一本好書給你。
轉行賣雞排吧你!
//
和 /* ... */
。
這陣子我們都看到一則新聞「碼農槍擊了4 名同事導致一人情況危急」,程式碼註解有多重要就不用再提了吧!
變數是儲存值的地方,又稱為符號佔位器(symbolic placeholder),例如:a = b + 1
中的 a 和 b。變數的作用是「管理程式的狀態」,讓我們能將程式中各種會變動的狀態(也就是值)存起來並搭配運算子組成運算式做一些運算。注意,JavaScript 是弱型別的語言,意即宣告變數、賦值後仍可改變值的資料型別。
// 用 var 宣告一個物件
var product = {
name: 'apple',
count: 100,
}
// 用 let 宣告一個有作用域限制的變數,範圍限於大括號內
let name = 'Nina';
ES6 使用 const
來宣告常數,代表這變數的值不會改變,在嚴格模式下還會報錯。
const PI = 3.14;
變數的命名必須要為有效的識別字,何謂有效?就是必須以 a-z、A-Z、$
(錢字號)或 _
(底線)開頭,之後可加上 a-z、A-Z、$
(錢字號)、_
(底線) 和數字 0-9,並且不可以是關鍵字或保留字。變數的命名規則同樣也適用於物件特性的命名,只是物件特性的名稱可為關鍵字或保留字。
var happy = 'happy'; // 這是合法的
var @@ = 'sad'; // 這是不合法的,報錯「Uncaught SyntaxError: Invalid or unexpected token」
var obj = { // 這是合法的,物件的特性可使用關鍵字或保留字命名
this: 'this is an object',
}
「關鍵字」(keyword)是指在目前 ECMAScript 中有特定用途的英文字詞,而「保留字」(reserved word)則是系統留用,雖然目前尚未用到但未來可能有其他用途的字彙。
再次強調,不管是關鍵字或保留字都不能做變數名稱使用。
區塊是由一對大括號(curly-brace pair,{ ... }
)所規範出來的範圍。
if (count > 10) {
// 區塊範圍在此...
}
表達條件式的方法有 if 述句、switch 述句、條件(三元)運算子和迴圈,以下分別述之。
const product = '100';
const shipment = 100;
const total = Number(product) + shipment; // 200
if (product > shipment) {
console.log('Buy it!');
} else {
console.log('Do not buy it!');
}
結果得到「Do not buy it!」。
const count = 50;
switch(count) {
case 0:
case 1:
case 2:
console.log('快賣完了!趕快進貨!');
case 50:
console.log('庫存充裕');
case 100:
console.log('是不是賣不掉了!?');
default:
console.log('運作正常');
}
但出乎意料的是,結果印出「庫存充裕、是不是賣不掉了!?、運作正常」。
庫存充裕
是不是賣不掉了!?
運作正常
這是因為如果沒有加入 break,一旦某個符合條件了,接下來的 case 無論符合與否都會被執行,也就是剛才所提到的「落穿而過」。
加入 break 修正一下。
const count = 50;
switch(count) {
case 0:
case 1:
case 2:
console.log('快賣完了!趕快進貨!');
break;
case 50:
console.log('庫存充裕');
break;
case 100:
console.log('是不是賣不掉了!?');
break;
default:
console.log('運作正常');
}
結果印出
庫存充裕
在 JavaScript 中會被轉為 false 的值有
""
空字串而除了以上之外,都會被轉為 true,舉例如下
'Hello World'
非空字串[], [1, 2, 3]
陣列,不管是不是空的{}, { name: 'Jack' }
物件,不管是不是空的function foo() {}
函式如果真的很不確定到底會轉成什麼,可以使用 !!
做測試
!![] // true
!!{} // true
!!NaN // false
重複一組動作,直到檢測條件不成立為止。迴圈的形式有很多種,最常用的就是 while 迴圈(while 或 do...while)和 for 迴圈兩種。
while 迴圈的構成有以下要素:測試條件和區塊,而每次執行區塊時就稱為一次迭代(iteration)。
while
vs do...while
兩者的差異在於 while
是先測後跑,而 do...while
是先跑後測。
來看第一個簡單的例子,。假設商品數量目前有五個,每賣掉一個就將庫存減一,當全賣完(及庫存為零)的時候就跳出迴圈,並印出「全部賣完了」的訊息。
let product = 5;
while (product > 0) {
console.log('買一個!');
product--;
console.log(`現在還剩 ${product} 個。`);
}
console.log('全部賣完了');
但下面這個例子就超有不同了,此時更改商品數量為零,剛剛提到 while 是「先測後跑」,因此當檢驗測試條件時,發現 product > 0
得到 false,也就不會進入區塊了,直接印出「全部賣完了」的訊息。
let product = 0;
while (product > 0) {
console.log('買一個!');
product--;
console.log(`現在還剩 ${product} 個。`);
}
console.log('全部賣完了');
再來看 while...loop
,這個例子並無異狀,跟第一個例子所得到的結果完全相同。
let product = 5;
do {
console.log('買一個!');
product--;
console.log(`現在還剩 ${product} 個。`);
} while (product > 0);
console.log('全部賣完了');
但是...剛剛提到 while...loop
是「先跑後測」,我們又將商品商品數量改為零,
此時會先進入區塊,依序印出「買一個!」、商品數量減一、顯示「現在還剩 -1 個。」,最後才檢驗測試條件,終止迴圈的執行,印出「全部賣完了」的訊息。
let product = 0;
do {
console.log('買一個!');
product--;
console.log(`現在還剩 ${product} 個。`);
} while (product > 0);
console.log('全部賣完了');
使用 break 跳出迴圈。
範例如下,在 product 為 2 的時候跳出迴圈。
let product = 5;
while (product > 0) {
console.log('買一個!');
product--;
console.log(`現在還剩 ${product} 個。`);
if (product === 2) {
console.log(`停停停,不要賣了!快進貨啊。`);
break;
}
}
console.log(`停賣後還剩 ${product} 個。`);
使用 continue 跳過本次迭代,迴圈依舊持續進行。
範例如下,在 product 為 2 的時候忽略之後要執行的 console.log(
現在還剩 ${product} 個。);
,直接進入下一次迭代。
let product = 5;
while (product > 0) {
console.log('買一個!');
product--;
if (product === 2) {
console.log(`第二個我要暗摃起來`);
continue;
}
console.log(`現在還剩 ${product} 個。`);
}
console.log('全部賣完了');
for 迴圈有三個子句-初始化子句、條件測試子句、更新子句。
let product = 5
product > 0
product--
for(let product = 5; product > 0; product--) {
console.log('買一個!');
console.log(`現在還剩 ${product} 個。`);
}
console.log('全部賣完了');
看完這篇文章,我們到底有什麼收穫呢?藉由本文可以理解到...
同步發表於部落格。
大大這篇寫完後,有沒有夢到 = a b,來找您,這一篇太神了
有夢到鐵人賽寫不完,哈哈哈
感謝大大不嫌棄,我會繼續加油!
寫不完的有兩種...
大大如果寫不完的情況,是
寧願要有品質,也不願少寫幾個字。
堅持是要用代價換來的,加油!!
感謝鼓勵,我會繼續加油!
寫得好用心,還有附梗圖!
我也很喜歡Skye,一開始也是因為她掉進神盾局的坑。
感謝大大的閱讀!
神盾局超好看的!