負責人:黃丰嘉
授課時間:2019-09-15 (日)
ECMAScript standard
。版本 | 正式名稱 | 備註 |
---|---|---|
1 | ECMAScript 1 (1997) | First Edition. |
3 | ECMAScript 3 (1999) | 廣泛支援 (2000 - 2010) |
5 | ECMAScript 5 (2009) | JS ES5 |
6 | ECMAScript 2015 | JS ES6 添加let 、const 、可以預設參數的值 |
8 | ECMAScript 2017 | 添加 Object |
9 | ECMAScript 2018 | 最新版 |
本節介紹JavaScript中,值(Value)的型別(types)和運算子(operators)。
JavaScript 是個「弱型別」的語言。
ES5標準,JavaScript 內建型別:
ES6 之後多了新的型別:Symbol
JavaScript 使用固定的 64 bits 來儲存數值。
值 (分數/尾數) | 指數 (表示次方數) | 正負號 |
---|---|---|
52 bits (0 - 51) | 11 bits (52 - 62) | 1 bit (63) |
不管整數或帶有小數點的數字,還是科學記號表示都是。
var x = 3.14; // A number with decimals
var y = 3; // A number without decimals
var x = 123e5; // 12300000
var y = 123e-5; // 0.00123
var z = 2.998e8; // 2.998 × 10^8 = 299800000
除了常見的數字外,還有3種特殊的數字。
Infinity
:正無限大。
console.log(Infinity - 1);
// Infinity
console.log(123 / 0);
// Infinity
-Infinity
:負無限大。
NaN
:不是數值(not a number),儘管它是 number type 的一種值(value)。
NaN 與任何數字作數學運算,結果都是 NaN。
NaN 並不等於任何的數字,甚至是自己。NaN === NaN; // false
console.log(typeof NaN);
//number
console.log(0 / 0);
// NaN
console.log(Infinity - Infinity);
// NaN
運算子 (Operators):+
、-
、*
、/
、%
運算順序:
()
,先運算*
除/
或取餘數%
,後加+
減-
使用""
(雙引號)、''
(單引號)或 `
,將字串包起來。
多行字串,可透過\
(反斜線)繼續。但\
後面不能有任何東西,包括空白字元。
console.log("Lie on the ocean");
console.log('Float on the ocean');
console.log(`Down on the sea`); //Backtick-quoted strings
console.log('這不是一行文 \
這是第二行 \
這是第三行');
倘若要在單引號內包覆單引號,或是雙引號內包覆雙引號就會出現問題。
console.log('Let's go!'); //SyntaxError
console.log("Let's go!");
\
(跳脫字元, escape character)處理 console.log('Let\'s go!');
樣板字面值(Template literal):
外部:由` `
包裹。
內部:由$
及{}
構成佔位符(${expression}
),允許字串嵌入運算式並返回運算結果。
console.log(`half of 100 is ${100 / 2}`);
// half of 100 is 50
運算子 (Operators):+
console.log("con" + "cat" + "e" + "nate"); //concatenate
布林值的值只有兩種:true 和 false,通常用於判斷式,作為控制程式流程的用途。
比較運算子:>
、<
、>=
、<=
、==
、!=
、===
、!==
console.log(3 > 2) // → true
console.log("a" < "Z") // → false
console.log("Aardvark" < "Zoroaster") // → true
console.log(NaN == NaN) // → false
字串比大小:
"a"
> 大寫字母"Z"
> 非字母的字元("!"
, "-"
…)嚴格相等(===
) vs. 一般相等(==
)
===
(或稱 "三等於"、"全等"):
不會
將型別一致化後比較(若型別不同,就回傳 fasle)。==
(或稱 "雙等於"):
邏輯運算子:&&
(and)、||
(or)、!
(not)
console.log(true && false); // → false
console.log(false || true); // → true
console.log(!false); // → true
Unary operators (一元運算子):只需要單個運算元,即可完成運算。
typeof
運算子,用於判斷型別種類。
console.log( -(-10) ); // → 10
console.log(typeof 4.5); // → number
console.log(typeof "x"); // → string
Binary operators (二元運算子):需要兩個運算元,才可完成運算。
console.log( 10 - 2); // → 8
ternary operator (三元運算子):需要三個運算元,才可完成運算。
語法:condition ? exprIfTrue : exprIfFalse
當條件符合,回傳中間的值(exprIfTrue),反之回傳右邊的值(exprIfFalse)。
console.log(true ? 1 : 2);
// → 1
console.log(false ? 1 : 2);
// → 2
Denote the absence of a meaningful value. They are themselves values, but they carry no information.
Two special values:
undefined
(未定義)
console.log(typeof undefined); //undefined
Boolean(undefined) //false
//當變數 a 被宣告時,在沒有給變數任何數值的情況下,變數的預設值是 undefined。
var a;
console.log(typeof a); //undefined
//將變數 a 的值,設定為""。資料型別變為 string。
var a = "";
console.log(typeof a); //string
null
(沒有值)
console.log(typeof null); //object
Boolean(null) //false
//當變數 b 被宣告時,則直接被明確地設定為 null。
var b = null;
console.log(typeof b); //object
//將變數 b 的值,設定為 null。資料型別仍為 object。
var b = {firstName:"John", lastName:"Doe"};
b = null;
console.log(typeof b); //object
當運算元的型別不同時,JavaScript 會自動依規則 type coercion (強制轉型)並運算。
console.log(8 * null); //null => 0
// → 0
console.log("5" - 1); //5 (from string to number)
// → 4
console.log("5" + 1); //1 (from number to string)
// → 51
console.log("five" * 2);
// → NaN
console.log(false == 0 && "" == false);
// → true
console.log(null == 0);
// → false
Three-character comparison operators
===
:嚴格相等
!==
:嚴格不相等
console.log(null == undefined); //true
console.log(null === undefined); //false (型別不同,直接回傳 fasle)
Such values are created by typing in their name (true, null) or value (13, "abc").
+
, -
, *
, /
, %
)+
)==
, !=
, ===
, !==
, <
, >
, <=
, >=
)&&
, ||
)-
to negate a number!
to negate logicallytypeof
to find a value’s type)?:
) to pick one of two values based on a third value.本節將學習JavaScript的語法結構。
JavaScript是以
;
來判斷一段程式碼的結束。
有無縮排,在JavaScript並不影響。建議還是縮排,因為方便閱讀程式碼區塊。
Expression
(運算式)
不完整
程式碼片段。!false
、"SIRLA"
、-( 2+3 )
相當於一個句子的某部分片段。
Statement
(敘述句)
完整
的程式碼,執行某個動作。console.log( -( 2+3 ) );
相當於一個完整的句子。
用以方便抓取或是儲存值(value)。
「弱型別」的JavaScript,變數本身不帶有資料型別的資訊,變數只用來作為取得值或物件的
參考
。
在執行時期,透過變數來參考
至物件或值,才會得知此變數有什麼操作方法。
用於宣告變數的保留字(keyword)
let
宣告區域變數。
let a = 5 * 5;
console.log(a); // → 25
let one = 1, two = 2;
console.log(one + two); // → 3
let mood = "light";
mood = "dark";
console.log(mood); // → dark
當參考到未給值的變數時,將得到undefined
。
let a;
console.log(a); // → undefined
var
(short for “variable”)
var
。const
(constant)
最常使用。
宣告常數,不能再作修改。
一經宣告,就永遠存在。
var name = "Ayda";
const greeting = "Hello ";
console.log(greeting + name); // → Hello Ayda
駝峰式命名:
FuzzyLittleTurtle
、fuzzyLittleTurtle
。
JavaScript 區分大小寫。
$
、_
,但不可有其他標點符號、特殊字元或空白(space)。
fuzzy_little_turtle
保留字
(keywords)。
當你用保留字
命名時,會出現syntax error。
break case catch class const continue debugger default
delete do else enum export extends false finally for
function if implements import interface in instanceof let
new package private protected public return static super
switch this throw true try typeof var void while with yield
//
/* */
console.log
函式於瀏覽器的控制台 (console)。
Windows 請按 F12
Mac 請按 command-option-I
let x = 30;
console.log("the value of x is", x); // → the value of x is 30
直線型的流程:
let Num = Number(prompt("輸入數字:"));
console.log("平方後的結果:" + Num * Num);
條件型的流程:
if
let Num = Number(prompt("輸入數字:"));
if (!Number.isNaN(Num)) {
console.log("平方後的結果:" + Num * Num);
}
if (1 + 1 == 2) console.log("It's true"); // → It's true
if ... else ...
let Num = Number(prompt("輸入數字:"));
if (!Number.isNaN(Num)) {
console.log("平方後的結果:" + Num * Num);
} else {
console.log("Hey. Why didn't you give me a number?");
}
if ... else if ... else ...
let Num = Number(prompt("輸入數字:"));
if (Num < 10) {
console.log("Small");
} else if (Num < 100) {
console.log("Medium");
} else {
console.log("Large");
}
迴圈型(loop)的流程:
while
符合條件後才做
let number = 0;
while (number < 8) {
console.log(number);
number = number + 2;
}
// → 0, 2, 4, 6
do ... while
先做再說
let yourName;
do {
yourName = prompt("Who are you?");
} while (!yourName);
console.log(yourName);
for
num = num + 2
相當於num += 2
counter = counter + 1
相當於counter += 1
相當於counter ++
for (let num = 0; num < 7; num = num + 2) {
console.log(num);
}
// → 0, 2, 4, 6
let result = 1;
for (let counter = 0; counter < 10; counter = counter + 1) {
result = result * 2;
}
console.log(result); // → 1024
break
:跳出迴圈。
以下範例程式碼的for迴圈內,缺少終止條件的檢查。
代表此迴圈將永不停止(無限迴圈),除非break statement
被執行。
for (let current = 20; ; current ++) {
if (current % 7 == 0) {
console.log(current);
break;
}
}
// → 21
continue
:跳出loop body
,但仍在迴圈內繼續跑。
for (let current = 20; current < 30; current ++) {
if (current % 2 == 0) {
continue;
}
console.log(current);
}
// → 21, 23, 25, 27, 29
分派型(dispatch)的流程:
switch
若case敘述內缺少
break
,switch將持續執行至含有break
的case才停止。
switch (prompt("What is the weather like?")) {
case "rainy":
console.log("Remember to bring an umbrella.");
break;
case "sunny":
console.log("Dress lightly.");
case "cloudy":
console.log("Go outside.");
break;
default:
console.log("Unknown weather type!");
break;
}
Input: sunny
Output: Dress lightly. Go outside.
本節將學習JavaScript函式的語法。
物件(Object)
的一種。函式的名稱 (也可能沒有名稱)
( )
中的部分,稱為「參數」。若有多個參數,則用,
隔開。
{ }
內的部分,放需要重複執行的運算。
function square(number) {
return number * number;
}
square(2); // 4
定義函式 (3種方式)
透過
return
回傳結果。若無,則預設會回傳 undefined。
函式宣告
function 名稱([參數]) {
...
}
function square(x) {
return x * x;
}
函式運算式
匿名函式
變數名稱 = function ([參數]) {
...
}
無參數
const makeNoise = function() {
console.log("Pling!");
};
makeNoise(); // → Pling!
console.log(typeof makeNoise); //function
有參數
若有兩個以上的參數,則用
,
隔開。
const square = function(x) {
return x * x;
};
箭頭函式
當箭頭函式無參數時,()
仍保留。
變數名稱 = ([參數]) => {
...
};
const power = (base, exponent) => {
let result = 1;
for (let count = 0; count < exponent; count++) {
result *= base;
}
return result;
};
在函式定義中,設定參數預設值
function power(base, exponent = 2) {
let result = 1;
for (let count = 0; count < exponent; count++) {
result *= base;
}
return result;
}
console.log(power(4)); // → 16
呼叫函式
因為JavaScript在編譯階段,自動將變數和函式定義先放入記憶體,
再去執行函式呼叫。
名稱([參數]);
const square = function(x) {
return x * x;
};
square(3); //9
若多給參數,則JavaScript會自動忽略多餘的參數,執行時不會出問題。
function square(x) {
return x * x;
}
console.log(square(4, true, "sirla")); // → 16
若少給參數,則預設缺少參數的值為undefined,執行時會出問題。
function minus(a, b) {
if (b === undefined) return -a;
else return a - b;
}
console.log(minus(10)); // → -10
console.log(minus(10, 5)); // → 5
變數作用的範圍,分為:
任何地方
使用。
全域變數:
var
區塊內
使用。
區域變數:
let
、const
let x = 10; //這裡的x為global
if (true) {
let y = 20;
var z = 30;
console.log(x + y + z); // → 60
}
// y is not visible here
console.log(x + z); // → 40
const halve = function(n) {
return n / 2; //這裡的n為local,與global的n之間無關係
};
let n = 10; //這裡的n為global
console.log(halve(100)); // → 50
console.log(n); // → 10
巢狀結構:
函式區塊內,再包裹函式。
外部函式區塊內的參數,可作用於內部函式。
const hummus = function(factor) {
const ingredient = function(amount, unit, name) {
let ingredientAmount = amount * factor;
if (ingredientAmount > 1) {
unit += "s";
}
console.log(`${ingredientAmount} ${unit} ${name}`);
};
ingredient(1, "can", "chickpeas");
ingredient(0.25, "cup", "lemon juice");
ingredient(2, "tablespoon", "olive oil");
ingredient(0.5, "teaspoon", "cumin");
};
console.log(hummus(2));
Output:
2 cans chickpeas
0.5 cup lemon juice
4 tablespoons olive oil
1 teaspoon cumin
狗跟貓的計數函式,輸出結果混在一起了
// 狗的計數函式
var count = 0
function countDogs () {
count += 1
console.log(count + ' dog(s)')
}
// 貓的計數函式
var count = 0
function countCats () {
count += 1
console.log(count + ' cat(s)')
}
countCats() // 1 cat(s)
countCats() // 2 cat(s)
countDogs() // 3 dog(s)
countDogs() // 4 dog(s)
countDogs() // 5 dog(s)
countCats() // 6 cat(s)
讓狗的計數函式只計算狗的,貓的計數函式只計算貓的。
讓變數保留在該函式中而不會被外在環境干擾。
// 狗的計數程式
function dogHouse () {
var count = 0
function countDogs () {
count += 1
console.log(count + ' dog(s)')
}
return countDogs
}
const countDogs = dogHouse()
// 貓的計數函式
function catHouse () {
var count = 0
function countCats () {
count += 1
console.log(count + ' cat(s)')
}
return countCats
}
const countCats = catHouse()
countCats() // 1 cat(s)
countCats() // 2 cat(s)
countDogs() // 1 dog(s)
countDogs() // 2 dog(s)
countDogs() // 3 dog(s)
countCats() // 3 cat(s)
進一步簡化程式,直接 return function
// 狗的計數程式
function dogHouse () {
var count = 0
return function () {
count += 1
console.log(count + ' dog(s)')
}
}
const countDogs = dogHouse()
// 貓的計數函式
function catHouse () {
var count = 0
return function () {
count += 1
console.log(count + ' cat(s)')
}
}
const countCats = catHouse()
countCats() // 1 cat(s)
countCats() // 2 cat(s)
countDogs() // 1 dog(s)
countDogs() // 2 dog(s)
countDogs() // 3 dog(s)
countCats() // 3 cat(s)
甚至運用同一個 dogHouse
時,變數間也都是獨立的執行環境不會干擾。
function dogHouse () {
var count = 0
function countDogs () {
count += 1
console.log(count + ' dog(s)')
}
return countDogs
}
var countGolden = dogHouse()
var countBlack = dogHouse()
var countPuppy = dogHouse()
countBlack() // 1 dog(s)
countBlack() // 2 dog(s)
countPuppy() // 1 dog(s)
countBlack() // 3 dog(s)
countGolden() // 1 dog(s)
countPuppy() // 2 dog(s)
countGolden() // 2 dog(s)
函式內不斷呼叫自己本身。
缺點:
function power(base, exponent) {
if (exponent == 0) {
return 1;
} else {
return base * power(base, exponent - 1);
}
}
console.log(power(2, 3)); // → 8
function printFarmInventory(cows, chickens) {
let cowString = String(cows);
while (cowString.length < 3) {
cowString = "0" + cowString;
}
console.log(`${cowString} Cows`);
let chickenString = String(chickens);
while (chickenString.length < 3) {
chickenString = "0" + chickenString;
}
console.log(`${chickenString} Chickens`);
}
printFarmInventory(7, 11);
Output:
007 Cows
011 Chickens
function printZeroPaddedWithLabel(number, label) {
let numberString = String(number);
while (numberString.length < 3) {
numberString = "0" + numberString;
}
console.log(`${numberString} ${label}`);
}
function printFarmInventory(cows, chickens, pigs) {
printZeroPaddedWithLabel(cows, "Cows");
printZeroPaddedWithLabel(chickens, "Chickens");
printZeroPaddedWithLabel(pigs, "Pigs");
}
printFarmInventory(7, 11, 3);
Output:
007 Cows
011 Chickens
003 Pigs
function zeroPad(number, width) {
let string = String(number);
while (string.length < width) {
string = "0" + string;
}
return string;
}
function printFarmInventory(cows, chickens, pigs) {
console.log(`${zeroPad(cows, 3)} Cows`);
console.log(`${zeroPad(chickens, 3)} Chickens`);
console.log(`${zeroPad(pigs, 3)} Pigs`);
}
printFarmInventory(7, 16, 3);
Output:
007 Cows
016 Chickens
003 Pigs
Declare g to be a function
function g(a, b) {
return a * b * 3.5;
}
console.log(g(1, 2));
Define f to hold a function value
const f = function(a) {
console.log(a + 2);
};
f(1);
A less verbose function value
let h = a => a % 3;
console.log(h(2));
var
let
、const
Minimum
function min(a, b) {
if (a < b){
return a;
}else{
return b;
}
}
console.log(min(0, 10)); // → 0
console.log(min(0, -10)); // → -10
const min = function(a, b) {
if (a < b){
return a;
}else{
return b;
}
};
let min = (a, b) => {
if (a < b){
return a;
}else{
return b;
}
}
Recursion
function isEven(n) {
if (n == 0) return true;
else if (n == 1) return false;
else if (n < 0) return isEven(-n);
else return isEven(n - 2);
}
console.log(isEven(50)); // → true
console.log(isEven(75)); // → false
console.log(isEven(-1)); // → false
Bean counting
function countChar(string, ch) {
let counted = 0;
for (let i = 0; i < string.length; i++) {
if (string[i] == ch) {
counted += 1;
}
}
return counted;
}
function countBs(string) {
return countChar(string, "B");
}
console.log(countBs("BBC")); // → 2
console.log(countChar("kakkerlak", "k")); // → 4