iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 8
0
Modern Web

小白的JavaScript讀書日記系列 第 8

Day8:彙整重複執行的程式 - 函式(一)

Day7的練習答案:
Try1:請計算2019.05.28到 2020.09.08過了多少日期。

let dat1 = new Date(2020,09,08);
let dat2 = new Date(2019,05,28);
let diff = (dat1.getTime()-dat2.getTime())/(1000*60*60*24);
console.log(diff);  //468

基本上就是將Day7例子中的日期換掉就好!
今天開始進入函式囉!



函式

什麼是函式? 不知道大家記不記得再Day4的時候有稍微提到 "函式是將某些輸入值(參數),已預先設定好的程序處理後,再回傳結果。"
那為什麼我們需要他呢? 常常我們會有一段或多段程式需要重複利用,這時候我們就可以用函式將它包裝起來,有需要用的時候就呼叫那個函式。
宣告方法等等介紹,但不管甚麼方式,都會包含幾個部分:

  • 名稱
  • 再括號()內的參數,參數與參數之間用逗號隔開
  • 再大括號{}內的部分,是重複執行的內容,是函式功能的主要區塊
    以下介紹幾種寫法:
// First 用function指令定義
function myFun(base, height){
    return (base * height)/2;
};
console.log('Ans:'+ myFun(20,10)); // Ans:100
//將 20 與 10帶入myFun
//執行 return (base + height)/2

// Second 用Function建構子定義
let myFun2 = new Function('base','height','return base * height/2');
console.log('Ans2:' + myFun2(20,10)); //Ans:100
//將程式用Function建構子來寫,但可讀性較差

//Third 用函式常值定義
let myFun3 = function(base, height){
    return (base * height)/2
}
console.log('Ans3:' + myFun3(20,10)); // Ans:100

//Forth 箭頭函式 ES6才出現
let myFun4 = (base,height) => base * height /2;
console.log('Ans4:' + myFun4(20,10)); // Ans:100

接下來比較一下四種在執行上的差別

// First 用function指令定義
console.log('Ans:'+ myFun(20,10)); // Ans:100
function myFun(base, height){
    return (base * height)/2;
};
// Second 用Function建構子定義
console.log('Ans2:' + myFun2(20,10)) //Ans:報錯:
//Uncaught ReferenceError: Cannot access 'myFun2' before initialization
let myFun2 = new Function('base','height','return base * height/2');
//Third 用函式常值定義
console.log('Ans3:' + myFun3(20,10)) // Ans:報錯
//Uncaught ReferenceError: Cannot access 'myFun3'
let myFun3 = function(base, height){
    return (base * height)/2;
};
// //Forth 箭頭函式 ES6才出現
console.log('Ans4:' + myFun4(20,10)) //Ans:報錯:
//Uncaught ReferenceError: Cannot access 'myFun2' before initialization
let myFun4 = (base,height) => base * height /2;

透過上述四種寫法,我們發現只有第一種function指令定義不會報錯,原因在於,其他三種都是在執行時才會解析,所以當我們將console.log('Ans:' + myFun(20,10))這段放到函式前時,就會出錯。

作用範圍(Scope) - 變數可被參考的區域

簡單來說就是全域變數與區域變數的差別,先簡單描述一下:

  • 全域變數:函式外宣告的變數
  • 區域變數:函式內宣告的變數

接著我們透過程式碼來解說:

let x = 10; //全域變數
function getValue(){
    let x = 100; //區域變數
    return x;
};
console.log(getValue()); //100
console.log(x); //10

透過上述的例子我們了解了,當我們執行了 console.log(getValue());,他會將函式內的區域變數(let x = 100;)傳入,所以是 100。
console.log(x);在這段程式碼中的x為什麼不是100卻是10呢?
因為再函式內定義的let x = 100;實際上只屬於在getValue這個涵式中,
所以當我們執行console.log(x); //10這段的時候他是找到let x = 10;這個x變數。

那如果function內沒有x變數呢?

let x = 10; //全域變數

function getValue(){
    return x
}
console.log(getValue()); //10
console.log(x); //10

如果function內沒有對應的變數,就會往外層找,直到全域變數為止,所以得到的是10。
這邊要注意的是,function可以讀取外層以宣告的變數,但外層沒辦法讀取function內所宣告的變數。

最後,我們將全域與區域變數以及函式的寫法合併起來觀察:

let x = 10; //全域變數
function getValue(){
    
    let x =100; //區域變數

    function myFun1(){return x;};
    console.log(myFun1()); // 100

    let myFun2 = function(){return x;};
    console.log(myFun2()); // 100

    let myFun3 = new Function('return x;');
    console.log(myFun3()); // 10

    let myFun4 = () =>  x;
    console.log(myFun4()); // 100
}
getValue();

透過以上程式碼,我們可以發現只有在myFun3得到的結果是不同的,這是為什麼呢?
原因是當使用Function建構子來定義函式,他參考的變數會是全域變數,因此得到的結果是10,因此Function建構子除了可讀性不佳以外,還有這個缺點,盡量在使用上避免。




今日總結

  • 函式的寫法與差異
  • 全域變數與區域變數的作用區域
  • 全域變數與區域變數,搭配上函式的應用及概念
  • Try1:
    let x = 20;
    function getValue(y){
        x = 30;
        return x+y;
    }
    console.log(getValue(10));
    console.log(x);
    
    求:
    console.log(getValue(10)); 結果?
    console.log(x); 結果?

呼,今天告一個段落囉,後續的文章如果可以都會用程式碼做解釋,除了加深我自己的印象之外,也希望大家可以動手做囉~ 明天見!


上一篇
Day7:基本資料操作-內建物件(二)
下一篇
Day9:中場murmur
系列文
小白的JavaScript讀書日記30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言