JavaScript
本篇為 [JS101] 用 JavaScript 一步步打造程式基礎 這門課程的學習筆記。如有錯誤歡迎指正!
JavaScript 是一種物件導向(Object-oriented programming)的腳本語言(Script language),主要用來改進 Web 瀏覽器的客戶端體驗。
腳本語言是一種直譯語言,因不需進行編譯,在撰寫和除錯上較為方便;但缺點是執行效率比不上編譯語言,且無法單獨執行,必須仰賴運行環境。例如:HTML 網頁中的 JavaScript 需要瀏覽器支援才能執行。
直到 Node.js 出現後,提供了 JavaScript 在瀏覽器以外的運行環境。目前實務開發中,通常使用瀏覽器的開發者工具來進行 debug(除錯)。
參考資料:
進入官網會看到下列文字: Node.js® is a JavaScript runtime built on Chrome's V8 JavaScript engine. (Node.js 一個能執行 JavaScript 的運行環境,以 Google Chrome V8 引擎為核心。)
安裝完成後,就可以在 Command Line 輸入指令:
node -v
:查看目前 Node.js 版本號出現版本號就代表安裝成功。
node
:直接在 CML 開啟 Node 環境可在終端機輸入指令。按 Crtl+C 或輸入就.exit
即可退出。
<script >
標籤內vim index.js
:輸入 vim 指令建立檔案 index.js,並且編輯內容也可使用 VSCode、Sublime 等程式碼編輯器來撰寫程式碼
node index.js
:在 CML 執行檔案 index.js若要輸出字串,需用 '單引號' 或 "雙引號" 括起來。
console.log(’Hello World’) // 輸出值:Hello World
+
:加
-
:減
*
:乘
/
:除
%
:取餘數(例如 10 % 3,結果是 1)
0
、""
、null
、false
、undefined
、NaN
||
:or只要其中一個是 true 就會返回 true,除非全部為 false。意即只要其中一個條件滿足就成立。
&&
:and全部為 true 才會是 true,否則均返回 false。意即全部條件都必須成立。
!
:not做反向。
||
與 &&
的短路性質使用最短的路徑來求值,又稱短路求值。只有當第一個運算數的值無法確定邏輯運算的結果時,才對第二個運算數進行求值。例如:
在這種情況下,就不需要知道第二個運算數的具體值。也就是短路性質。
範例:
var obj = obj || { }; // 如果 obj 存在就維持原樣,如果不存在就給予空物件
var student = name || "小明"; // 如果沒有 name 就用預設為小明。用 || 來設定變數預設值
更多短路邏輯的運用可參考這篇:想知道&&與&及||與|之間的區別嗎? | 程式前沿
<<
與 >>
首先來複習二進位制:
0100 = 2^30 + 2^21 + 2^10 + 2^00 = 2^2 = 4 1000 = 2^31 + 2^20 + 2^10 + 2^00 = 2^3 = 8
and or xor not (待補)
++
與 --
++
,increment):運算前或運算後「遞增」--
,decrement):運算前或運算後「遞減」其中以 ++ 運算子為例:
++ 運算子的回傳值,取決於相對於運算元的位置。
++a
):用在運算元之前,執行遞增,然後回傳遞增後的值。a++
):用在運算元後方,執行遞增,然後回傳未遞增前的值。若以邏輯運算為例:
'Hello World'
typeof <value>
:用來判斷參數型態在 MDN 網站 列出 typeof 的可能回傳值:
null 使用 typeof 運算子,回傳的結果會是字串 "object",這指出 null 可被認為是象徵「無物件」(no object)的一種特殊物件值。(參考資料:犀牛書)
這其實是 JavaScript 最初發現的一個錯誤,然後被 ECMAScript 沿用了。現在,null 被認為是物件的佔位符,從而解釋了這一矛盾 (參考資料:你懂JavaScript 嗎?#4 型別(Types) )
宣告變數
是將這個箱子取名,加上等號賦值
是在裡面裝東西var this_is_a_box
var thisIsABox
前面提到變數是像箱子的儲存模型,參考 Huli 寫的這篇文章,舉以下範例來說明其特性:
==
與 ===
是去看「格子的內容」是否相等,而不是檢查「所代表的東西」是否相等。解決方法:
console.log(Number(a) + b)
:用 Number()
將字串轉成數字console.log(parseInt(a, 10) + b)
:用 parseInt()
將字串轉換成整數,10 代表預設的十進位==
與 ===
=
:代表賦值
==
和 ===
:均用來判斷是否相等
差別在於 ===
會判斷「型態」:
永遠都用三個等號,如此最能夠避免型態不同而發生錯誤。
在寫程式時遇到重複的動作,一定有方法能夠優化。
由 console.log(1 === 1)
,會回傳 true 這個例子,來判斷下列情形:
結果卻是:
變數是一個箱子,在放入數字的情況下:
但如果在變數裡放入物件,結果卻會如下:
可以想像成「記憶體位置」:儘管兩個箱子儲存的數值相同,但因記憶體位置不同,指向的元素不同,所以不會相等。
如果換成下列情形:
兩者理所當然會相等,但若將 obj2.a = 2
:更改 obj2 物件中 a 的值,會連 obj 的值也一起更動:
會發現 obj 的值也一起被更改了。這是因為 obj 和 obj2 指向同一個記憶體位置,指向同一個物件。
但如果 obj2 = {b:1}
:obj2 等於一個新的物件,會指向一個新的記憶體位置:
這是因為「往裡面放東西」與「改放全新的東西」是兩件完全不同的事情。後者會指向一個新的記憶體,可參考下圖理解:
判斷式在 JavaScript 中用來控制流程。當指定的條件成立時,就會執行後續的指令。判斷式的語法有兩種:if...else
和 switch
。
if-else
statementelse if
,用來新增條件判斷else if
可以有很多個case 條件:
後方都會加上 break
:用途是停止執行後面的程式碼,否則 switch
會從匹配的 case
標籤開始執行到尾端===
運算子判斷),亦即型別也要相同參考資料:
以判斷是否及格為例:
Ctrl+C
跳出)for (;;)
會是無窮迴圈break
(中斷):中斷整個迴圈語句,也就是「跳出」迴圈區塊執行結果如下圖:
continue
(繼續):繼續下一次迴圈語句,會忽略在 continue 之後的語句,直接跳到下一次的迴圈開頭執行結果如下圖:
以前學的國中數學 y = f(x)
其實就是一種函式:
在 JavaScript 的函式架構:
範例:在陣列產生 n 個元素的函式
也可以不寫 return,寫法如下:
範例:印出 1~100 的偶數
小技巧:不知如何解題時,可先從寫下 Function 架構開始
要產生 1~100 的數字,可能需要迴圈:
需要再寫一個函式,來判斷 i 是否為偶數:
function
關鍵字作函數的宣告和定義。我們在先前的範例,console.log() 都只傳入數字、字串等,但其實也可傳入函式,如以下範例:
上述範例中,在 transform 函式裡面,double 函式取代了參數 transformFunction,也就是執行 double 函式內部的運算。
也可直接把整組函式丟到 console.log() 括號內,就不需再額外命名。好處是可直接修改函式定義,如以下範例:
參數:方法定義中的變數 引數:在呼叫方法時真正傳入的值
結果如下圖,印出 { '0': 2, '1': 5 }
。
由上述範例可知,arguments
物件其實是種「類陣列物件」。
並且具有 length 屬性。
參考MDN - Arguments 物件,由於 arguments 帶其他屬性,可能因此需要用物件的方式來儲存資訊。
例外情況是數字.字串.布林,這三者較簡單,所以在操作的時候會變成直接複製。而較複雜的部份因為使用指向的方式,所以只要有一個地方修改,就等修改其他指向該記憶體位置的操作。
在這邊的操作是把 obj 指向了另外一個新的記憶體,等於 obj 指向了另外一個記憶體位置
這種情況以專有名詞稱作:
pass by value pass by reference. (JavaScript 中沒有) pass by sharing
首先可以把 function 分成兩類:
也就是只需要呼叫 function,但不需知道執行結果的情況。
也可以回傳些什麼,如以下範例,但 return 並不會影響結果。
例如需要函式進行運算,然後回傳結果。
注意:在 function 一旦執行 return 就會跳出,return 以下的任何程式碼都不會再執行。
可參考: Number - JavaScript - MDN - Mozilla Math - JavaScript - MDN - Mozilla
Number()
:將字串轉數字parseInt()
:將字串轉整數。預設為十進位,例如:parseInt(a, 10)
parseFloat()
:將字串轉浮點數。也就是有小數點toFixed()
:取到小數點後第幾位。括號內不輸入就會取整數。可與 parseFloat()
搭配使用.toString()
:數字轉字串或是將數字加空字串(''
),因為「數字 + 字串 = 字串
」。
Number.MAX_VALUE
, Number.MIN_VALUE
:得知在 JavaScript 可儲存的最大、最小值,若超出這個值,計算就會不精準Math.PI
:圓周率。常數通常用大寫表示Math.ceil()
:無條件進位,取大於這個數的最小整數Math.floor()
:無條件捨去,取小於這個數的最大整數Math.round()
:四捨五入Math.sqrt()
:開根號Math.pow()
:次方Math.random()
:產生從 0~1 隨機數(不包含 1)toUpperCase
, toLowerCase()
:將字串轉換大、小寫或是參考 ASCII code 進行轉換:
.charCodeAt()
:取得字串特定位置的字元 ASCII 編碼String.fromCharCode()
:將 ASCII 編碼的數字轉換成字元利用 ASCII code 進行字串比大小,可判斷該字元為大小寫、是否在條件範圍內:
indexOf()
:可回傳「指定字串」在字串中第一次出現的位置。若找不到則回傳 -1replace()
:取代字串。只能換第一個指定字串。要全換的話可使用正規表達式來達成split()
:透過「指定分隔符」來分開字串,回傳值為陣列trim()
:移除目前字串開頭和結尾的所有空格string.length
:可回傳字串長度。此指令不是函式可應用在迴圈:
join.()
:將陣列中所有元素連接成一個字串,預設分隔符是逗號(在 Windows 系統)map()
:把陣列中的每個元素帶入指定函式,然後建立一個新的陣列filter()
:概念和 map()
類似,是根據指定的測試函數,從一個陣列中過濾出符合條件的元素,並建立新的陣列slice()
:可截取出陣列某部份元素,會建立一個新的陣列splice()
:可用來刪除與新增元素,會改變原本的陣列sort()
:依照字母順序排列陣列中的所有元素,會改變原本的陣列除了物件以外,其他基本型別(primitive types)具有不可變的特性。
以內建函式 toUpperCase()
為例,如以下寫法:
由於字串具有不可變的特性,不論呼叫什麼函式均無法改變 a 的值,如以下範例:
而物件型別,例如 Array,呼叫某些函式的時候,有可能會更動到原本記憶體位置儲存的東西:
參考資料: