iT邦幫忙

0

Javascript 進階 5-3 參數

這個章節要來介紹參數

前幾篇的文章對參數有一些介紹,這篇文章會對參數的各種狀態進行更詳細的介紹。

在介紹參數之前,一個函式在運行之前,會帶入那些參數。

var globalVariables = '全域變數';
var obj = {
    afunction: function (para) {
        var localVariables = '區域變數';
        console.log(para, localVariables, arguments, this, globalVariables);
    }
};

// 執行
obj.afunction('一段描述', 2, 3);

我們可以看到,這段程式碼在執行的時候帶入的參數是3個,但接受的 function 只有 para 一個參數,也就是說,para 這個參數只會對應到 一段描述 這個字串,其他的2、3沒有傳進去。

看一下執行的結果~

https://ithelp.ithome.com.tw/upload/images/20200103/201217700abXrd6oas.png

我們可以看到 globalVariables 以及 localVariables都有對應到正確的值,而全域變數之前的章節也有討論過,如果找不到就會向外尋找直到找到為止,不然就回傳 not defined。

this的部分後面會再詳細的討論,這裡就先跳過。

重點是又多了一個 arguments 的變數,而且他好像是一個陣列,裝著'一段描述', 2, 3 的三個值。

但其實這個 arguments 被稱作 類陣列 ,但其實他不是陣列。雖然它可以被 for 迴圈處理內部的資料,但對於大部分陣列操作的指令他都無法執行。

Hoisting 影響參數的運行

function callName (a) {
    console.log(a); // 小明
}

callName('小明');

上述執行的結果應該很明顯就是小明沒有甚麼好講的對吧~

那麼如果改成下面這樣呢?

function callName (a) {
    console.log(a); // 小明
    
    var a;
    console.log(a); // 小明
}

callName('小明');

其實執行起來也還是小明喔!

原因是因為,我們再宣告一個變數的時候,這個變數名稱已經存在的時候,這個宣告就是無效的。
所以 var a; 是無效的,自然 a 就還是保持在小明的狀態。

那接下來我們把 a 改成 杰倫 呢?

function callName (a) {
    console.log(a); // 小明
    
    var a;
    console.log(a); // 小明
    
    a = '杰倫';
    console.log(a); // 杰倫
}

callName('小明');

這時候就會是杰倫了,所以要改變內部的參數,直接覆蓋就可以了!

那麼重頭戲來了喔~!

如果我今天在裡面定義的是 函式陳述式呢?

根據之前學過的觀念是,函式陳述式會最早被寫入在記憶體空間中。

我們來實際操作看看

function callName (a) {
    console.log(a); 
       
    function a () {}
       
    var a;
    console.log(a); 
    
    a = '杰倫';
    console.log(a); 
}

callName('小明');

https://ithelp.ithome.com.tw/upload/images/20200103/20121770vhUOEBewuB.png

很明顯在 a 還沒被杰倫覆蓋之前,傳入的小明就被 函式陳述式 給附蓋了。

所以雖然 函式陳述式 會最早被寫入在記憶體空間中,但最早是指在這個函式內的 {} 的最早。

因此 函式陳述式 並不會比 '小明' 這個參數還早,所以顯示的結果才是 函式陳述式

定義的參數名稱的規則

我們再定義函式接收的參數名稱的時候,注意的只有參數的數量,參數的名稱都是可以自定義的,只要不要重複就好。

我們接下來來看看下面的例子:

function callMore (d,c,b,a){
    console.log(d,c,b,a);
}
var a = 'a';
var b = 'b';
var c = 'c';
callMore(a, b ,c);

目前雖然傳了3個參數進去,但函式接受的參數定義是4個,因此最後一個 a 就會在函式內被定義為 undefined。

傳入參數是物件類型的資料,依然會維持傳參考的特性

看一下範例吧~!

function callObject (obj) {
    obj.name = '杰倫家';
}
var family = {
    name: '小明家'
}
callObject(family);
console.log(family);

所以這邊執行後的結果很明顯就是 family.name 會被改成 杰倫家。

https://ithelp.ithome.com.tw/upload/images/20200103/20121770mPqzUA5YoK.png

這邊也要提醒一下,盡量避免傳入物件類型的資料後,又在函是內部修改資料內容,避免不預期的結果。

當然也是有人利用這種特性進行撰寫,但其實這樣的撰寫風格不易追蹤,維護成本也較高。

因此不太建議這麼寫。

CallBack Function

function FnB (fn) {
    fn('小明');
}

FnB(function (a) {
    console.log(a);
});

這樣的函式直接執行,我們就先把參數預定在 FnB 中,等到執行的時候,傳入ㄧ個 function,而 function 就會接收到 FnB 中的參數,並做ㄧ些處理。

我們也可以改寫成

function callSomeone (name) {
    console.log(name + '你好');
}
function FnB (fn) {
    fn('小明');
}
FnB(callSomeone);

這樣的寫法,我們把 callSomeone 賦予到 FnB 的參數 fn上。

我們是透過函式表達式的方式傳入到 FnB 的 function 中,因此真正執行的地方是在 callSomeone 的 function 裡面。

而這樣呼叫的方法呢,我們又稱作 callback function。

類陣列 Arguments

剛剛有說到 arguments 是一個類陣列,每個函是在運行的時候都會有,他不需要特別宣告就可以取用。

他會接受所有傳進來的值,並以一個類似陣列的結構乘裝著,但他不是真正的陣列。

function callArg (a) {
    console.log(a, arguments);
}
callArg(1,2,3,'a','5');

https://ithelp.ithome.com.tw/upload/images/20200103/201217705GApMtxkrx.png

我們可以對這個 arguments 做 for 迴圈的取值動作

function callArg (a) {
    console.log(a, arguments);
    
    for (var i = 0; i < arguments.length; i ++) {
        console.log(arguments[i]);
    }
}
callArg(1,2,3,'a','5');

https://ithelp.ithome.com.tw/upload/images/20200103/20121770noililLqnR.png

但我們就沒辦法對她使用 forEach 的方法

function callArg (a) {
    console.log(a, arguments);
    
    arguments.forEach(function () {});
}
callArg(1,2,3,'a','5');

https://ithelp.ithome.com.tw/upload/images/20200103/20121770jVJvjMCYsO.png

關於甚麼是類陣列,在這個章節還不需要先學習。

只要知道 arguments 是在函是運行的時候自帶的變數,並且會乘裝ㄧ切傳入的值,這樣就可以嚕~

沒有問題的話我們就可以往下一篇文章邁進了! 希望對各位有幫助~汪汪!


尚未有邦友留言

立即登入留言