## 陣列、函式、變數 ---- #### 課程聊天室:https://tlk.io/mrtjs ![課程聊天室](https://i.imgur.com/R9qiCXX.png) --- ## 陣列 JS 並沒有明確的陣列資料類型。取而代之,提供了 Array 物件。與物件不同的是,陣列可以經由特定的 index 取得、改變陣列中的元素 (element)。 ---- ```javascript=1 var obj = {propertyA: 1} var arr = [0,1,2]; ``` |功能|物件|陣列| |--|--|--| |取得|`obj.propertyA`|`arr[0]`| |更新|`obj.propertyA = 2`|`arr[0] = 2`| |新增|`obj.propertyB = 'B'`|`arr[3] = 3`| ---- :boom: ```javascript=1 var arr = [0,1,2]; arr[5] = 5 // [0,1,2, empty, empty, 5] arr[3] = undefined ``` ---- Exercise ```javascript=1 var arr = ['20191225']; var obj = {time1: '20191224'} // console.log(arr, obj) // ['20191224'], {time1: '20191224', time2: '20191225'} ``` ---- #### 常用內建函式 from [oxxostudio](https://www.oxxostudio.tw/articles/201908/js-array.html) |分類 |方法| | -------- | -------- | | 會改變原始陣列 | push()、pop()、shift()、unshift()、reverse()、splice()、sort()、copyWithin()、fill() | 回傳陣列元素資訊或索引值 | length、indexOf()、lastIndexOf()、find()、findIndex()、filter() | 針對每個元素處理 | forEach()| ---- |分類 |方法| | -------- | -------- | | 產生新的陣列或新的值 | join()、concat()、slice()、map()、reduce()、reduceRight()、flat()、flatMap()、Array.from()、Array.of()、toString() | 判斷並回傳佈林值 | every()、some()、includes()、Array.isArray() ---- * 改變原始陣列 - push() ```javascript=1 var arr = [{name: 'a'}, {name: 'b'}]; arr.push({name: 'c'}); conole.log(arr) // [ {name: "a"}, {name: "b"}, {name: "c"}] ``` ---- * 得到陣列資訊 - length ```javascript=1 var arr = [{name: 'a'}, {name: 'b'}]; console.log(arr.length) // 2 ``` ---- * 不回傳,針對陣列每一元素做處理 - forEach() ```javascript=1 var arr = [{name: 'a'}, {name: 'b'}]; arr.forEach(function(person) { person.name = 'c' }) console.log(arr); // [ {name: "c"}, {name: "c"}] ``` ---- * 產生新的陣列或新的值 - map() ```javascript=1 let arr = [{name: 'a'}, {name: 'b'}]; arr = arr.map(function(person) { return person.name }); console.log(arr); // ['a', 'b'] ``` ---- * 判斷並回傳佈林值 - every() ```javascript=1 var arr = [{name: 'a'}, {name: 'b'}]; arr.every(function(person) { return typeof(person.name) === 'string' }) // true ``` ---- Exercise ```javascript=101 // 產生只有 {id, title} 的 array var newReleases = [ { "id": 70111470, "title": "Die Hard", "rating": [4.0], "bookmark": [] }, { "id": 654356453, "title": "Bad Boys", "rating": [5.0], "bookmark": [{ id: 432534, time: 65876586 }] } ] function generateKeyArr(value) { let result; ... return result; } console.log(generateKeyArr(newReleases)) // [ // { // "id": 70111470, // "title": "Die Hard" // }, // { // "id": 654356453, // "title": "Bad Boys" // } // ] ``` --- ## 函式 - 組成元素 * 函式的名稱。 * 包圍在括號()中,並由逗號區隔的一個函式參數列表。 * 包圍在大括號{}中,用於定義函式功能的一些JavaScript語句。 ---- ```javascript=1 function square(number) { return number * number; } square(4) // 16 ``` ---- Exercise ```javascript=1 function plus(number1, number2) { ... } console.log(plus(4, 2)); console.log(plus('4', 2)); console.log(plus(4, '2')); ``` ---- Exercise ```javascript=1 var person = {name: 'chad'}; function modifyObj(obj) { ... } modifyObj(person); console.log(person); // {name: 'peter'} ``` ---- Exercise ```javascript=1 var name = 'chad'; function modifyValue(name) { ... } modifyValue(name); console.log(name); // peter ``` ---- :bomb:將變數傳進函式時,發生了什麼事?[Reference](https://blog.techbridge.cc/2018/06/23/javascript-call-by-value-or-reference/) ![Pass by Value](https://static.coderbridge.com/img/techbridge/images/huli/value/value.gif) ---- ![對 x 賦值](https://i.imgur.com/5DJII3i.png) ---- ![對 y 賦值](https://i.imgur.com/BDl9mey.png) ---- ![函式建立](https://i.imgur.com/Jsapyae.png) ---- ![temp 建立](https://i.imgur.com/O19bQ5H.png) ---- ![對 a 賦值](https://i.imgur.com/aMoxjjN.png) ---- ![對 b 賦值](https://i.imgur.com/oDYMSWZ.png) ---- ![](https://static.coderbridge.com/img/techbridge/images/huli/value/p1.png) ---- ```javascript=1 var person = {name: 'chad'}; function modifyObj(obj) { obj.name = 'peter'; } modifyObj(person); console.log(person); ``` ---- ```javascript=1 var person = {name: 'chad'}; function modifyObj(obj) { obj.name = 'peter'; } modifyObj(person); console.log(person); ``` | 名稱 | 記憶體位置 | 儲存的值 | | -------- | -------- | -------- | | | 0x01 | `{name: 'chad'}` | ---- ```javascript=1 var person = {name: 'chad'}; function modifyObj(obj) { obj.name = 'peter'; } modifyObj(person); console.log(person); ``` | 名稱 | 記憶體位置 | 儲存的值 | | -------- | -------- | -------- | | | 0x01 | `{name: 'chad'}` | | person | 0x02 | 0x01 | ---- ```javascript=1 var person = {name: 'chad'}; function modifyObj(obj) { obj.name = 'peter'; } modifyObj(person); console.log(person); ``` | 名稱 | 記憶體位置 | 儲存的值 | | -------- | -------- | -------- | | | 0x01 | `{name: 'chad'}` | | person | 0x02 | 0x01 | | obj | 0x03 | 0x01 | ---- ```javascript=1 var person = {name: 'chad'}; function modifyObj(obj) { obj.name = 'peter'; } modifyObj(person); console.log(person); ``` | 名稱 | 記憶體位置 | 儲存的值 | | -------- | -------- | -------- | | | 0x01 | {name: <del>'chad'</del> 'peter'} | | person | 0x02 | 0x01 | | obj | 0x03 | 0x01 | ---- ```javascript=1 var person = {name: 'chad'}; function reassignObj(obj) { obj = { name: 'peter' }; } reassignObj(person); console.log(person); ``` ---- ```javascript=1 var person = {name: 'chad'}; function reassignObj(obj) { obj = { name: 'peter' }; } reassignObj(person); console.log(person); ``` | 名稱 | 記憶體位置 | 儲存的值 | | -------- | -------- | -------- | | | 0x01 | `{name: 'chad'}` | | person | 0x02 | 0x01 | ---- ```javascript=1 var person = {name: 'chad'}; function reassignObj(obj) { obj = { name: 'peter' }; } reassignObj(person); console.log(person); ``` | 名稱 | 記憶體位置 | 儲存的值 | | -------- | -------- | -------- | | | 0x01 | `{name: 'chad'}` | | person | 0x02 | 0x01 | | obj | 0x03 | 0x01 | ---- ```javascript=1 var person = {name: 'chad'}; function reassignObj(obj) { obj = { name: 'peter' }; } reassignObj(person); console.log(person); ``` | 名稱 | 記憶體位置 | 儲存的值 | | -------- | -------- | -------- | | | 0x01 | `{name: 'chad'}` | | person | 0x02 | 0x01 | | obj | 0x03 | 0x04 | | | 0x04 | `{name: 'peter'}` | ---- #### :bomb: > 將變數傳進函式時,發生了什麼事? Pass by value: 傳值,這個 <b>值</b> 有時候代表記憶體位置,有時候代表儲存的值。 --- ## 變數 ---- 宣告方式 * var * const * let ---- var * ES6 以前 * 可對已宣告變數再次宣告 ```javascript=1 var a; // undefined var a = 1; // 1, 可以重複宣告 a = 2; // 2; ``` ---- var * ES6 以前 * 可對已宣告變數再次宣告 * 可同時宣告多個變數 ```javascript=1 var a = 0, b = 0; ``` ---- Exercise ```javascript=1 var x = y, y = 'A'; console.log(x + y); ``` ---- scope - 變數的有效範圍 ### function scope ```javascript=1 function change() { var a = 1; console.log(a); } change(); ``` ---- scope - 變數的有效範圍 ### function scope ```javascript=1 function change() { var a = 1; console.log(a); } function change2() { var a = 2; console.log(a); } change(); change2(); ``` ---- scope - 變數的有效範圍 ### function scope ```javascript=1 var a = 1; function change() { console.log(a); } change(); ``` ---- scope - 變數的有效範圍 ### function scope ```javascript=1 var a = 1; function change() { var a = 2; console.log(a, "我在 function 'change' 裡面") } change(); console.log(a) ``` ---- scope - 變數的有效範圍 ### function scope ```javascript=1 var a = 1; function change() { var a = 2; console.log(a, "我在 function 'change' 裡面") } change(); for(var a=0; a < 5; a++) { } console.log(a); ``` ---- scope - 變數的有效範圍 ### [立即執行函式 IIFE](https://developer.mozilla.org/zh-TW/docs/Glossary/IIFE) ```javascript=1 var a = 1; function change() { var a = 2; console.log(a, "我在 function 'change' 裡面") } change(); (function(){ // 刻意創造一個立刻執行的函式,創造 scope,避免迴圈的宣告行為影響全局的變數 var a = 1; for(var a=0; a < 5; a++) { } })() console.log(a); ``` ---- ### function scope <br/> ###### `var` 在 `function` 內部建立 scope ###### 換句話說,如果在非 `function` 的狀況下使用 `var` ###### 有相當大的機會污染外部變數 ---- var * ES6 以前 -> <i>較舊的用法</i> * 可對已宣告變數再次宣告 * 可同時宣告多個變數 * function scope -> <i>新的版本提出解決方案</i> ---- #### scope - 變數的有效範圍 ### block scope ```javascript=1 let x = 'Hello from the new world'; const y = 'Hello from the new world'; ``` ---- ### let * 可重新 assign ```javascript=1 let a = 1; a = 2; a = {}; a = '3'; ``` ---- ### let * 可重新 assign * 不可重複宣告 ```javascript=1 let a = 1; let a = 2; // Uncaught SyntaxError: Identifier 'a' has already been declared ``` ---- ### let * 可重新 assign * 不可重複宣告 * block scope ```javascript=1 let a = 1; function change() { let a = 2; console.log(a, "我在 function 'change' 裡面") } change(); for(let a=0; a < 5; a++) { } console.log(a); ``` ---- ### const * 不可重新 assign ```javascript=1 const a = 1; a = 2; // Uncaught TypeError: Assignment to constant variable. ``` ---- ### const * 不可重新 assign ```javascript=1 const a = {name: 'chad'}; a.name = 'peter' ``` ---- ### const * 不可重新 assign ```javascript=1 const a = {name: 'chad'}; a.name = 'peter' // 更改物件中的屬性值並不會更改 a 指向的記憶體位置,所以不算重新 assign ``` |名稱|記憶體位置|儲存的值| |--|--|--| ||0x01|{name: <del>'chad'</del> 'peter'}| |a|0x02|0x01| ---- ### const * 不可重新 assign ```javascript=1 const a = {name: 'chad'}; a = { name: 'peter'}; // Uncaught TypeError: Assignment to constant variable. ``` |名稱|記憶體位置|儲存的值| |--|--|--| ||0x01|`{name: 'chad'}`| |a|0x02|<del>0x01</del> 0x03| ||0x03|`{name: 'peter'}`| ---- ### const * 不可重新 assign * 不可重複宣告 ```javascript=1 const a = 1; const a = 2; // Uncaught SyntaxError: Identifier 'a' has already been declared ``` ---- ### const * 不可重新 assign * 不可重複宣告 * block scope ```javascript=1 const a = 1; function change() { const a = 2; console.log(a, "我在 function 'change' 裡面") } change(); console.log(a); // 1 ``` ---- ### const * 不可重新 assign * 不可重複宣告 * block scope ```javascript=1 const a = 1; function change() { const a = 2; console.log(a, "我在 function 'change' 裡面") } change(); for(const a=0; a < 5; a++) { // 這裡就會出錯了: Uncaught TypeError: Assignment to constant variable. // 針對現代的瀏覽器, for 迴圈裡最好運用 let 宣告變數 } console.log(a); ``` ---- ## 變數 |宣告|重新 assign|重複宣告|scope|同時宣告多變數 |-|-|-|-|-| |`var`|可|可|function scope|可| |`let`|可|不可|block scope|可| |`const`|不可|不可|block scope|可| ---- ### hoisting - 提升 ###### 執行任何程式碼前,JavaScript 會把函式宣告及變數放進記憶體裡面 ---- ### hoisting - 提升 ```javascript=1 console.log(a); ``` ---- ### hoisting - 提升 ```javascript=1 console.log(a); // undefined var a = 2; ``` ---- ### hoisting - 提升 ```javascript=1 // var a; console.log(a); // undefined a = 2; ``` ---- ### hoisting - 提升 ```javascript=1 function catName(name) { console.log("My cat's name is " + name); } catName("Tigger"); ``` ---- ### hoisting - 提升 ```javascript=1 catName("Tigger"); function catName(name) { console.log("My cat's name is " + name); } ``` ---- ### hoisting - 提升 ###### function declaration 函式陳述式 ```javascript=1 catName("Tigger"); function catName(name) { console.log("My cat's name is " + name); } ``` ---- ### hoisting - 提升 ###### function expression 函式表示式 ```javascript=1 console.log(catName); // undefined catName("Tigger"); // error var catName = function(name) { console.log("My cat's name is " + name); } ``` ---- ### hoisting ###### const / let - temporal dead zone ```javascript=1 console.log(a); //TDZ const a = 1; ``` ```javascript=1 console.log(a); //TDZ let a = 1; ``` ---- ### hoisting ###### const / let - temporal dead zone ```javascript=1 var a = 10 function test() { console.log(a); // 如果 const / let 僅只是沒有 hoisting, 上一行應該為 10 let a; } test() ``` ---- ### hoisting ###### const / let - temporal dead zone [「提升之後」(在最前面宣告但不進行初始化)<br/>以及「賦值之前」這段「期間」](https://blog.techbridge.cc/2018/11/10/javascript-hoisting/) ```javascript=1 function test() { var a = 1; // c 的 TDZ 開始 var b = 2; console.log(c) // 錯誤 if (a > 1) { console.log(a) } let c = 10 // c 的 TDZ 結束 } test() ``` ---- ### hoisting 的原因 * 先宣告變數才可以使用 * 先宣告函式才可以使用 * 達成 function 互相呼叫 <br/> <br/> ##### 總結:盡量主動先宣告再使用 ```javascript=1 function test() { var a = 1; let b = 2; const c = 3; console.log(a, b, c); } test() ``` ---- # 陣列、函式、變數 ---- Ref: 1. [JavaScript Array 陣列操作方法大全 ( 含 ES6 )](https://www.oxxostudio.tw/articles/201908/js-array.html) 2. [深入探討 JavaScript 中的參數傳遞:call by value 還是 reference?](https://blog.techbridge.cc/2018/06/23/javascript-call-by-value-or-reference/) 3. [我知道你懂 hoisting,可是你了解到多深?](https://blog.techbridge.cc/2018/11/10/javascript-hoisting/) 4. [MDN 提升(Hoisting)](https://developer.mozilla.org/zh-TW/docs/Glossary/Hoisting) 5. [MDN var](https://developer.mozilla.org/zh-TW/docs/Web/JavaScript/Reference/Statements/var) 6. [MDN const](https://developer.mozilla.org/zh-TW/docs/Web/JavaScript/Reference/Statements/const) 7. [MDN let](https://developer.mozilla.org/zh-TW/docs/Web/JavaScript/Reference/Statements/let) ---- [範例程式](https://hackmd.io/@ChadZ/JS-MRT-2-EXERCISE)
{"metaMigratedAt":"2023-06-15T02:43:20.046Z","metaMigratedFrom":"YAML","title":"陣列、函式、變數","breaks":true,"slideOptions":"{\"title\":\"JavaScript 讀書會\",\"theme\":\"night\",\"transition\":\"slide\",\"spotlight\":{\"enabled\":false},\"transitionSpeed\":\"fast\"}","contributors":"[{\"id\":\"7da0a1a8-6add-40a7-9acc-950070ff069c\",\"add\":15368,\"del\":2144}]"}
    658 views