###### tags: `JavaScript` `JS 直播班` # 周末任務 - 變數宣告、傳值傳參考、undefined及null :::info 📕 **筆記大綱介紹** - var、let、const 的差異 - by reference (傳參考)、by value(傳值)概念 - undefined 與 null 的差異 ::: ## var、let、const 的差異 ### 為什麼要宣告變數? 變數在程式運行中扮演很重要的角色,我們可以將資料存放進變數內,並在需要的時候引用。 ### JS 三種宣告變數方式 1. var 2. const 3. let ### var : 時代的眼淚 - var 的問題:能夠被重複宣告 var 可以被重複宣告,而且不會出錯!想要天下大亂是逆?!! ```javascript= var weather = "天氣晴"; function fn() { var weather = "下大豪雨"; console.log(weather); // output: 下大豪雨 } fn(); console.log(weather); // output: 天氣晴 ``` - var 的問題2:作用域的汙染 在for迴圈上體驗凡響!!! ```javascript= for (var i = 0; i < 3; i++) { console.log(i); // output: 0,1,2 } console.log("i", i); // output: 3 ``` ### let、const : ES6推出的解決方法 ES6 推出可以使用範圍寫法的概念。 ### let 解決 var 缺點的瑰寶 - 不能被重複宣告 : 會幫你噴錯除錯喇! Identifier 'a' has already been **declared** :arrow_right: 已經被宣告過啦! ``` let a = 1; let a = 2; // output: Uncaught SyntaxError: Identifier 'a' has already been declared ``` - 可以區分作用域 : 沒有問題的喇! ```javascript= var teacher = "血汗校長"; // 全域變數 function changeTeacher(){ let teacher = "漂釀老師"; // 區域變數 teacher = "帥氣工友"; console.log(teacher); // output: 帥氣工友 } changeTeacher(); console.log(teacher); // output: 血汗校長 ``` - 改善for迴圈的汙染 i is not defined :arrow_right: 還沒定義過喇! ```javascript= for (let i = 0; i < 3; i++) { console.log(i); } console.log(i); // Uncaught ReferenceError: i is not defined ``` ### const : 定義常數就用我 > 常數 : 不能被變更的變數。 - 重新宣告會出錯窩~ Identifier 'pi' has already been declared :arrow_right: 已經被宣告過啦! (還想改圓周率阿(誤XD ```javascript= const pi = 3.14159265359; console.log(pi); // output: 3.14159265359 pi = 3; console.log(pi); // output: Uncaught SyntaxError: Identifier 'pi' has already been declared ``` - 有個例外:常數裡的陣列,想不到吧~ 因為陣列存放記憶體的方式是指向記憶體位置,所以想要修改裡面的內容,是可以的! ```javascript= const family = { dadName: 'David', momName: 'Amy' }; family.dadName = 'Yappy'; console.log(family); // output: {dadName: 'Yappy', momName: 'Amy'} ``` #### Object.freeze() :thinking_face: 可以解決嗎? YES! 來試試看 `Object.freeze()` JS的內建語法吧~ Identifier 'objUrl' has already been declared :arrow_right: 已經被宣告過啦! ```javascript= const objUrl = { urlIndex: "https://www.google.com/", }; // 使用 freeze 就不能修正了 Object.freeze(objUrl); objUrl.urlIndex = "https://tw.yahoo.com"; console.log(objUrl.urlIndex); // output: Uncaught SyntaxError: Identifier 'objUrl' has already been declared ``` ## by value(傳值)、by reference (傳參考) ### JS 的型別,主要有兩種 了解傳值還是傳參考前,得先知道型別有哪些~ - Primitive type : 原始型別處理值 - Object types : 物件處理參考 ### Primitive 的成員 - String - Number - Boolean - Null - Undefined ### Object - Object - Function - Array - Set ### by value(傳值) :writing_hand: 舉例來說... 1. 我先創造了變數a,並且賦值 "Hello world!" 2. 這是在電腦記憶體內創造了型別為字串的記憶體空間,並存放 "Hello world!" 進去 3. 再將變數a指向剛剛設定的記憶體空間 (目前進度只有到 `let a = "Hello world!";` 喔~) 4. 第二階段: 創造b變數 5. **另開一個記憶體**並將a記憶體空間內的值複製 6. 將b變數指向這個複製人(值: "Hello world!") 7. 第三階段: a指向新的記憶體空間: "JS is FUN!" 8. 查看大家的結果啦~ :star: 最大的重點就是,a、b的值是不會互相被影響,**賦值完**你我就是陌生人囉! ```javascript= let a = "Hello world!"; let b = a; a = "JS is FUN!"; console.log("a", a); console.log("b", b); // output: a JS is FUN! // output: b Hello world! ``` ### by reference (傳參考) >在JavaScript裡,物件、陣列、函式都是call by reference。 :star: 我本身就是個記憶體空間,不管你怎麼指都會指到同個位址啦! ```javascript= let people = { greeting : '安安!' }; let minions = people; minions.greeting = 'Bello~'; console.log("people", people); console.log("minions", minions); //output: people {greeting: 'Bello~'} //output: minions {greeting: 'Bello~'} ``` 挖!全部都變成小小兵LA~~ 這就是**傳址**,一修改記憶體內容,有指向的全部都被更改了> < ## undefined && null ### undefined (不明確的) 代表一種型態,變數宣告了,但目前還沒有值。 1. 一般變數 ```javascript= let a; console.log(a); //output: undefined ``` 2. 物件沒有這個**屬性** ```javascript= var family = { dad: "David", mom: "Annie", son: "Sowut" }; console.log(family.daughter); //output: undefined ``` 3. 函式沒有回傳值你硬要調用捏 :face_with_raised_eyebrow: ```javascript= function calc() {} console.log(calc()); //output: undefined ``` 4. 函式有傳入值就任性不給(? ```javascript= function payMoney(dollar) { console.log(dollar); //output: undefined 員工QQ } payMoney(); ``` :santa: 補充: is not defined :arrow_right: 這個變數還沒被宣告喇! ```javascript= console.log(b) //output: b is not defined ``` ### null 空值 - 硬是被給的,刻意使變數為空值 - 若想要利用js抓取節點(dom),如果沒有這個值會返回空給你看(阿人家就沒有~) ```javascript= const elTitle = document.getElementById('jsTitle'); console.log(elTitle); // output: null ``` ### 比較一下 #### 型別差很多耶~ - undefined : 原始型別就有我本人 undefined - NaN : 無法計算的數字型別 number - null : 一種物件型態 ```javascript= typeof undefined //output: 'undefined' typeof NaN //output: 'number' typeof null //output: 'object' ``` #### 真假值 如果使用寬鬆比較(兩個==),會為真,因為兩個false去比較。但如果我們用更嚴謹的比較方法(三個===),他有協助我們去比較型態,就會是相反的結果了。 ```javascript= console.log(undefined == null); // output: true console.log(undefined === null); // output: false ``` ## 📚 參考閱讀資源 >**1. [語法與型別](https://developer.mozilla.org/zh-TW/docs/Web/JavaScript/Guide/Grammar_and_types)** >[name=MDN WEB Docs] >**2. [ECMAScript6 入門:var、let、const 差異](https://w3c.hexschool.com/blog/530adff5)** >[name=Sealman] >**3. [var、let、const 的差異?](https://hackmd.io/m7wJAmCUSsqUDFjFefY1Vw?view)** >[name=guitimliu] >**4. [JavaScript 的「傳值」與「傳址」](https://hackmd.io/@chupai/B13YRDJJB)** >[name=竹白] >**5. [JavaScript null、undefined 與 undeclared](https://kim85326.github.io/2019/09/09/JavaScript-null-undefined-%E8%88%87-undeclared/)** >[name=Elaine's Blog]