熟悉前幾篇的 p5.js 基本繪圖技巧後便可進一步來學習繪製動態圖形. 之前我們都只是呼叫 p5.js 的內建函式來繪圖, 完全不需要用到 Javascript 語法來控制, 但對於較複雜或動態的圖形時則需要用到 Javascript 的判斷與迴圈等語法功能, 本篇摘要整理 Javascript 語法, 做為學習 p5.js 動態圖形繪製前複習之用.
本系列之前的文章參考 :
以下測試使用之參考文件 :
# https://p5js.org/reference/ (教學文件)
# https://editor.p5js.org (線上編輯器)
Javascript 教學文件參考 :
1. 基本語法 :
Javascript 語法摘要整理如下表 :
語法 | 說明 | 範例 |
註解 | 不會被執行的說明文字 | //這是單行註解 /*這是多行註解 繼續註解 註解結束*/ |
識別字 | 有分大小寫, 只能用字母, 底線, 前號, 與數字, 但首字元不能是數字 | var c2c; var $2a; var _foo$; |
基本型態 | 數值 (整數, 浮點數) 字串 (單雙括號均可) 布林 (true/false) | var i=2; var a=3.14159; var a=6.626e-34; var a="foo"; var a='bar'; alert(a.length) //字串長度 var a="Hello" + "world"; //字串用 + 串接 var a=true; var a=false; |
基本物件 | 使用 new 運算子建立之 物件 (有 prototype). | var obj=new Object(); //Object 物件 var s=new String("123"); //字串物件 var b=new Boolean("true"); //布林物件 var n=new Number("123"); //數值物件 var arr=new Array(3); //陣列物件 var r=new RegExp("[Jj]avascript", "g"); //正規式物件 var date=new Date(); //日期物件 var f=new Function("a", "b", "return a+b"); //函式物件 也可用對應之包裹器函式建立物件 (去掉 new 即可) |
全域屬性 與方法 | 不須建立物件即可使用 | infinity : 無限大 NaN : 非數值 undefined : 未定義 isNaN() : 檢查 a 是否為非數值 (true/false) isFinite(a) : 檢查 a 是否為有限值 (true/false) |
運算子 | 算術運算子 關係運算子 邏輯運算子 位元運算子 指定運算子 條件運算子 | +, -, *, / (四則運算), % (餘數), ++ (遞增), -- (遞減) >, <, <=, >=, ==(值), !=, === (值與型), !=== (值或型) && (且), || (或), ! (非) & 且, | 或, ^ XOR, ~ 非, << 左移, >> 右移, >>> 有號右移 =, +=, -=, *=, /=, %=, &=, |=, <<=, >>=, >>>= r=b? x: y (若 b 為 true 則 r=b 否則 r=y) |
判斷 | if (條件式1) { 敘述1; } else if (條件式2) { 敘述2; } else { 敘述4; } 條件式為 true 時執行 (0, none, undefined, 空字串, NaN 為 false) | //判斷成績等級 A~E var score=parseFloat(prompt("請輸入成績:")); if (score < 60) {var grade="E";} else if (score < 70 && score >= 60) {var grade="D";} else if (score < 80 && score >= 70) {var grade="C";} else if (score < 90 && score >= 80) {var grade="B";} else {var grade="A";} |
分支 | switch (運算式) { case 值1 : { 敘述1; break; } case 值2 : { 敘述2; break; } default : { 預設敘述; } } 運算式的值可以是 : 1. 數值 2. 字串 3. 布林 當 case 均不符時執行 default, 每個 case 必須以 break 結束. | var today=new Date(); var day=today.getDay(); switch (day) : { case 0: {var weekday="週日"; break;} case 1: {var weekday="週一"; break;} case 2: {var weekday="週二"; break;} case 3: {var weekday="週三"; break;} case 4: {var weekday="週四"; break;} case 5: {var weekday="週五"; break;} case 6: {var weekday="週六"; break;} default: {var weekday="錯誤!";} } |
迴圈 | //for 迴圈 for (初始; 條件; 更新) { 敘述; } for (鍵 in 物件) { 敘述; } for (索引 in 陣列) { 敘述; } for (元素 of 陣列) { 敘述; } //while 迴圈 while (條件式) { 敘述; //至少執行0次 } //do 迴圈 do { 敘述; //至少執行1次 } while (條件式); | //for 迴圈 : 計算 1+2+3+...+10 var total=0; for (var i=0; i<=10; i++) { total += i; } //走訪物件項目 var obj={'a': 1, 'b': 2, 'c':3}; for (k in obj) { //for in 迭代鍵 var v=obj[k]; console.log(k + ":" + v); } //走訪陣列元素 //for in 迭代索引 var arr=[1, 2, 3]; for (idx in arr) { console.log(arr[idx]); } //走訪陣列元素 //for of 迭代元素 (只能用在陣列/字串) var arr=[1, 2, 3]; for (e of arr) { console.log(e); } //while 迴圈 : 計算 1+2+3+...+10 var total=0; var i=0; while (i <= 10) { total += i; ++i; } //do 迴圈 : 計算 1+2+3+...+10 var total=0; var i=0; do { total += i; ++i; } while (i <= 10); |
函式 | function 名稱([參數]) { 敘述; [return 傳回值;] } 參數=原生型態 : 傳值 參數=物件/陣列 : 傳址 | function sum(a, b) { return a+b; } var s=sum(1, 2); |
物件 | {鍵1:值1, //屬性 鍵2:值2, //屬性 ... function:{ //方法 運算式; } } | obj={a:1, b:2, c: 3} var obj={ firstName:'foo', //屬性 lastName:'bar', //屬性 getFullName: function() { //方法 return this.firstName + ' ' + this.lastName; }; |
陣列 | arr.length 陣列長度 建立陣列可在中括號 [ ] 內放以逗號隔開之元素 (literal 法), 或用 new Array(n) 建立 n 個元素之空陣列, 但若傳入 1 個以上整數, 這些整數卻是元素. new Array() 只能建立一維陣列, 二維陣列必須使用迴圈. | //一般陣列 var arr=['a', 'b' ,'c']; //建立一個 3 元素之陣列 var arr=new Array(); //建立不定長度之空陣列 var arr=new Array(3); //建立一個長度為 3 的空陣列 arr[0]='a'; //新增元素 arr[1]='b'; //新增元素 arr[2]='c'; //新增元素 var arr=new Array(1, 2, 3); //建立內容 [1, 2, 3] 之陣列 var arr=new Array('a', 'b','c'); //建立一個陣列 ['a','b','c'] //二維陣列 var arr=[[1, 2], [3, 4]] //建立 2*2 陣列 var arr=new Array(2); for (var i=0; i<2; i++) { //建立 2*2 空陣列 arr[i]=new Array(3); } arr[0][0]=1; arr[0][1]=2; arr[1][0]=3; arr[1][1]=4; //關聯式陣列 var fruit={"apple":"蘋果", "papaya":"木瓜"}; alert(fruit["apple"]); //蘋果 |
條件運算子有兩種寫法, 一是運算結果指派給單一變數的, 例如 :
另外一種是問號後面有兩個運算式的, 例如 :
for in 可用在陣列與物件, 迭代的對象是陣列索引或物件之鍵 (key, 屬性); for of 迴圈只能用在陣列, 迭代的對象是陣列元素. 陣列的 forEach() 方法也可以用來走訪陣列, 迭代之對象為元素.
2. 輸出入函式 :
Javascript 用來輸出資料的方式有下列四種 (可用來除錯或輸出) :
Javascript 輸出方式 | 說明 |
alert(str) | 在輸出視窗中顯示變數 str 之值 |
document.write(str) | 在網頁內容 (body) 輸出變數 str 之值 |
document.getElementByID(myID).innerHTML(str) | 將 id=myID 的網頁元素內容以 str 取代 |
console.log(str) | 在瀏覽器主控台輸出變數 str 之值 |
從使用者取得資料的輸入方式有兩種 :
Javascript 輸入方式 | 說明 |
prompt(msg [, default]) | 彈出輸入視窗, msg=提示訊息, default=預設值, 傳回值為字串型態 |
confirm(msg) | 彈出確認視窗, msg=詢問訊息, 傳回值為 true (確定)/false (取消) |
注意, prompt() 的傳回值是字串, 在進行計算前應該呼叫下列函式進行轉換 :
型態轉換函式 | 說明 |
parseInt(s) | 將傳入參數轉成整數, 傳回整數或 NaN, 例如 parseInt("3.14") |
parseFloat(s) | 將傳入參數轉成浮點數, 傳回浮點數或 NaN, 例如 parseFloat("3.14") |
3. 字串操作 :
Javascript 內建包裹函式 String() 可將其他物件轉成字串物件, 其 length 屬性表示字串長度 (字元數), 常用的方法如下表 :
字串物件的方法 | 說明 |
toLowerCase() | 將字串中的英文字母轉成小寫 |
toUpperCase() | 將字串中的英文字母轉成大寫 |
charAt(index) | 傳回字串索引 index (0 起始) 之字元 |
charCodeAt(index) | 傳回字串索引 index (0 起始) 之字元的 unicode 編碼 |
fromCharCode(c) | 傳回 unicode 編碼為 c 的字元, 例如 "".fromCharCode(65) 傳回 'A' |
indexOf(str [, index]) | 傳回從 index 開始找尋子字串 str 第一次出現的位置, 未找到傳回 -1 |
lastIndexOf(str) | 傳回從字串尾端向前找尋子字串第一次出現之位置, 未找到傳回 -1 |
match(str) | 從頭開始搜尋子字串 str, 找到傳回 str, 否則傳回 null |
search(str) | 與 indexOf() 功能相同, 但 search() 可傳入正規式, indexOf() 不可 |
replace(str1, str2) | 將字串中的子字串 str1 全部以 str2 取代, 傳回結果字串 |
split(str) | 以子字串 str 分割字串, 成功傳回陣列, 失敗傳回字串本身 |
substr(index,length) | 從索引 index 開始取出長度 length 的子字串傳回 |
substring(a, b) | 從字串索引位置 a 開始至 b-1 取出子字串傳回 (a, b 不可為負) |
slice(a, b) | 從字串索引位置 a 開始至 b-1 取出子字串傳回 (a, b 可為負) |
concat(str) | 將子字串 str 串接到字串後面之後傳回 |
repeat(n) | 將字串重複 n 次後傳回 (ECMA 6) |
注意, 用 split() 以跳行為界拆分字串時可用 split("\n"), split("\n\r") 或 split("%0D%0A").
另外還有如下與網頁文字格式相關的字串物件方法 (有些在 HTML5 已不支援) :
字串物件的方法 | 說明 | HTML5 |
anchor() | 傳回錨點標籤 : <a>字串</a> | O |
big() | 傳回放大字型文字標籤 : <big>字串</big> | X |
blink() | 傳回閃爍文字標籤 : <blink>字串</blink> | X |
bold() | 傳回粗體文字標籤 : <b>字串</b> | O |
fixed() | 傳回打字機格式文字標籤 <tt>字串</tt> | X |
fontcolor(color) | 傳回字型文字標籤 : <font color="color">字串</font> | X |
fontsize(size) | 傳回字型文字標籤 : <font size="size">字串</font> | X |
italics() | 傳回斜體文字標籤 : <i>字串</i> | O |
link(url) | 傳回超連結標籤 : <a href="url">字串</a> | O |
small() | 傳回縮小字型文字標籤 : <small>字串</small> | O |
strike() | 傳回刪除文字標籤 : <strike>字串</strike> | X |
sub() | 傳回上標文字標籤 : <sub>字串</sub> | O |
sup() | 傳回下標文字標籤 : <sup>字串</sup> | O |
4. 陣列操作 :
Javascript 最常用的資料型態為陣列, 其 length 屬性表示元素之個數, 陣列物件之方法如下 :
陣列物件的方法 | 說明 |
push(e) | 將元素 e 放入陣列尾端 (新增元素) |
pop() | 取出陣列最後一個元素傳回並從陣列中刪除該元素 |
shift() | 取出陣列第一個元素傳回並從陣列中刪除該元素, 其餘元素往前移 |
unshift(e1, e2, ...) | 將元素 e1, e2, ... 依序放入陣列最前面 (從索引 0), 原來元素往後挪 |
slice(a, b) | 將陣列索引 a 至索引 b-1 之元素 (不含索引 b) 組成子陣列傳回 |
splice(a, n) | 將陣列索引 a 開始的 n 個元素刪除, 其餘元素往前移 |
join(str) | 將陣列全部元素以 str 字串串接後傳回 (字串) |
toString() | 將陣列全部元素以逗號 "," 串接後傳回, 等於 join(",") |
sort([f]) | 將陣列全部元素依字串值 (或比較函式 f 之傳回值) 遞增排序 |
reverse([f]) | 將陣列全部元素依字串值 (或比較函式 f 之傳回值) 遞減排序 |
indexOf(e) | 傳回元素 e 的索引, 若 e 不存在傳回 -1 |
forEach(function(e){}) | 透過匿名函式走訪陣列元素 |
5. 數學函式 :
Math 物件是 Javascript 較特殊的內建物件, 它沒有建構函式, 而是直接用 Math 調用其屬性與方法 (Math 類似 Java 中的靜態類別), 其屬性定義了常用之數學常數如下表 :
Math 物件之屬性 | 說明 |
Math.E | 自然指數 e=2.718281828459045 |
Math.LN2 | 2 的自然對數=0.6931471805599453 |
Math.LN10 | 10 的自然對數=2.302585092994046 |
Math.LOG2E | e 以 2 為底之對數=1.4426950408889633 |
Math.LOG10E | e 以 10 為底之對數=0.4342944819032518 |
Math.PI | 圓周率=3.141592653589793 |
Math.SQRP1_2 | 1/2 的平方根=0.7071067811865476 |
Math.SQRT2 | 2 的平方根=1.4142135623730951 |
Math 物件的方法 :
Math 物件的方法 | 說明 |
Math.max(a, b) | 傳回 a, b 中較大者 |
Math.min(a, b) | 傳回 a, b 中較小者 |
Math.abs(a) | 傳回 a 之絕對值 |
Math.pow(a, b) | 傳回 a 的 b 次方 |
Math.sqrt(a) | 傳回 a 的平方根 |
Math.round(a) | 傳回 a 的四捨五入到整數 |
Math.ceil(a) | 傳回 a 的無條件進位到整數 |
Math.floor(a) | 傳回 a 的無條件捨去到整數 |
Math.sin(a) | 傳回 a 的正弦值 |
Math.cos(a) | 傳回 a 的餘弦值 |
Math.tan(a) | 傳回 a 的正切值 |
Math.asin(a) | 傳回 a 的反正弦值 |
Math.acos(a) | 傳回 a 的反餘弦值 |
Math.atan(a) | 傳回 a 的反正切值 |
Math.exp(a) | 傳回 a 的自然指數值 |
Math.log(a) | 傳回 a 的自然對數值 (以 e 為底) |
Math.random() | 傳回 0~1 的隨機數 (精度 : 小數點後 16 位) |
常用的數學技巧 :
常用對數 (以 10 為底) =Math.LOG10E * Math.log(a)
0~100 之亂數=Math.floor(Math.random() * 100)
四捨五入到小數點後一位=Math.round(a * 10)/10
四捨五入到小數點後兩位=Math.round(a * 100)/100
四捨五入到小數點後三位=Math.round(a * 1000)/1000
求商=Math.floor(a/b)
6. 正規表達式 :
Javascript 的正規式有兩種表示法 :
- 斜線表示法 : 正規式用前後斜線包圍, 例如 var reg=/Javascript/i;
- 建構式表示法 : 呼叫內建函式 var reg=RegExp("Javascript", "i"),
其中 i 為比對方式, 共有三種 :
- i : 不分大小寫
- g : 全部比對
- ig 或 gi : 不分大小寫全部比對
正規表示法定義如下之特殊字元用來表示特定之字元與其排列方式 :
特殊字元 | 說明 | 範例 |
. | 比對換行 \n 以外的任何字元 | a.b 匹配 a1b, acb |
^ | 比對字串的開始位置 | ^ab 匹配 abc, 不匹配 cab |
$ | 比對字串的結束位置 | ab$ 匹配 cab, 不匹配 abc |
* | 比對前一個字元或分組出現 0 次以上 | ab* 匹配 a, ab, abb, abbb |
+ | 比對前一個字元或分組出現 1 次以上 | ab+ 匹配 ab, abb, abbb |
? | 比對前一個字元或分組出現 0 或 1 次 | ab? 匹配 a, ab, 不匹配 abb |
{m} | 比對前一個字元或分組剛好出現 m 次 | ab{2} 匹配 abb, 不匹配 abbb |
{m,} | 比對前一個字元或分組至少出現 m 次 | ab{2,} 匹配 abb, abbb, 不匹配 ab |
{m, n} | 比對前一個字元或分組出現 m~n 次 | ab{2, 3} 匹配 abb, abbb, 不匹配 abbbb |
\ | 跳脫後面的特殊字元, 以一般字元處理 | a\+ 匹配 a+bbb |
[] | 匹配括弧內的任一字元 | [abc] 匹配 12a34, 7cb54a |
[-] | 匹配 - 前後範圍內之任一字元 | [a-z] 匹配任一小寫字母 |
[^] | 匹配不是 ^ 後面所列舉之任一字元 | [^a-d] 匹配任一不是 a, b, c, d 之字元 |
() | 匹配括號內正規式者為一群組 | a(.+)b 匹配 a2b, 不匹配 ab |
\d | 匹配數字, 等於 [0-9] | [\d] 匹配任一數字字元 |
\D | 匹配非數字, 等於 [^0-9] | [\D] 匹配任一非數字字元如 W, a, ... |
\w | 匹配字母, 數字, 底線, 等於 [a-zA-Z0-9_] | \w 匹配 a, A, 0, _ |
\W | 匹配非 \w, 等於 [^a-zA-Z0-9_] | \W 匹配 !, @, + 等 |
\s | 匹配空白字元, 等於 [\f\r\n \t\f] (含空格) | [a\sb]+ 匹配 a bc 中的 a b |
\S | 匹配非空白字元, 等於 [^\f\r\n \t\f] | [a\S]+ 匹配 a bc 中的 abc |
\b | 匹配英文字的邊界 | \bm\w 匹配 monday 之 mo |
\B | 匹配非英文字的邊界 | \w\Bm 匹配 mommy 之 mm |
\cX | 匹配控制字元 X | \cM 匹配 Cntl+M |
\xhexXX | 匹配 16 進制 ASCII 編碼 XX 之字元 | \xhex41 匹配字元 A |
\ooctalOO | 匹配 8 進制 ASCII 編碼 OO 之字元 | \ooctal81 匹配字元 A |
\n | 匹配換行字元 | |
\r | 匹配回車字元 (carriage return) | |
\t | 匹配定位字元 (Tab) | |
\v | 匹配垂直定位字元 | |
\f | 匹配換頁字元 (form feed) |
這些特殊字元中 ^ 與 ? 都各有兩種不同用法, 容易混淆 :
- 正規式的多重量詞 * 或 + 預設是貪婪比對, 亦即會比對出最多字元, 但只要在重複量詞 * 或 + 後面添加? 即可改成懶惰比對, 即匹配字元越少越好.
- ^ 字符放在中括號內表示 Not (非, 否定) 意思, 但在中括號外則表示字串的開始位置.
正規式的搜尋比對可用 RegExp 物件或 String 物件的方法, 但取代則需使用 String 物件之 replace() 方法 :
RegExp 物件方法 | 說明 |
reg.test(str) | 用 RegExp 物件 reg 比對字串 str, 比對成功傳回 true, 失敗傳回 false |
reg.exec(str) | 用 RegExp 物件 reg 比對字串 str, 將匹配的所有子字串以陣列傳回 |
String 物件方法 | 說明 |
str.search(reg) | 用 RegExp 物件 reg 比對字串 str, 傳第一次出現位置之索引 (否則 -1) |
str.match(reg) | 用 RegExp 物件 reg 比對字串, 將匹配的所有子字串以陣列傳回 |
str.replace(reg, str1) | 用 RegExp 物件 reg 比對字串, 將匹配的部分以 str1 取代 |
沒有留言:
張貼留言