JavaScript 核心觀念(37)-函式以及 This 的運作-參數

前言

參數,參數在開發上是非常重要的觀念,最主要與函式有相關。

參數

首先先看一段範例程式碼

1
2
3
4
5
6
7
8
9
10
var globalName = 'Ray';

var obj = {
fn: function(name) {
var localName = 'Ray is Good!';
console.log(name, localName, globalName, arguments, this);
}
}

obj.fn(globalName, 'qq 先生', '2');

上面範例程式碼我們可以看到 obj.fn 中的 console.log 有相當多的東西

首先我們可以看到 obj.fn(globalName, 'qq 先生', '2'); 傳入了三個參數,但 fn 可以接受的參數只有一個也就是 name,這時候你可能會問這邊的函式只能接受一個,那麼這個 name 所接受的參數會是哪一個?答案是第一個,程式碼將會由第一個依序載入,因此一個 name 出現的結果是 Ray,而在此 console.log 的第二個則是 localName,但這並不屬於傳入的,而是基於在函式內所宣告的區域變數,那麼第三個就不用說了,則是全域變數。

接下來講一點比較特別得東西也就是 arguments

arguments

arguments 是一個非常特別的東西,基本上不論你傳入多少參數 arguments 都可以通通取得,但是這邊要注意一件事情 arguments 是一個類陣列

什麼是類陣列呢?簡單來講就是一個類似陣列但不是陣列的東西,但是類陣列與陣列最大差異在於可以使用的方法 or 功能會有很大差異,因此我們來看一下範例

1
2
var a = ['1', '2', '3'];
console.dir(a);

上面可以這邊建立了一個陣列實字,然後當你丟到瀏覽器運行時,我們可以點開該陣列的 __proto__,可以看到有相當多可以使用的方法與功能。

陣列方法

那麼前面一直在講的 arguments 呢?(避免資訊量太大所以稍微刪減)

1
2
3
4
5
6
7
8
var globalName = 'Ray';
var obj = {
fn: function(name) {
console.log(arguments);
}
}

obj.fn(globalName, 'qq 先生', '2');

類陣列

因此我們可以了解到,雖然它看似是一個陣列,但實際上與真正的陣列相差非常多,光可以使用的方法就差了很多,因此我們都會稱之為類陣列。

arguments 並不需要我們宣告與建立,因為當函式被執行時 arguments 就會被自動生成並建立唷。

函式內的參數宣告

接下來我們來講講宣告在函式內的變數與傳入的參數當若相同時會發生什麼事情。

1
2
3
4
5
6
7
8
9
var qq = 'jack';

function fn(qq) {
console.log(qq); // jack
var qq;
console.log(qq); // jack
}

fn(qq);

我們可以當函式內的變數名稱若與函式本身的參數相同時,並不會因為重新宣告而覆蓋原有的參數內容,因此在此宣告是無效的。

但若將 qq 重新賦予值是被允許的

1
2
3
4
5
6
7
8
9
10
11
var qq = 'jack';

function fn(qq) {
console.log(qq); // jack
var qq;
console.log(qq); // jack
qq = 'Ray';
console.log(qq); // Ray
}

fn(qq);

因此我們可以發現到函式的參數也是變數的一種,因此當若我們要修改參數的值時,就只能用重新賦予的方式,那麼就有一個疑問了,函式內的參數是否會受到提升的效果呢?答案是會的。

1
2
3
4
5
6
7
8
9
10
11
12
var qq = 'jack';

function fn(qq) {
console.log(qq); // qq function
function qq() {}
var qq; // 注意函式具有比變數更高的優先權,因此重新宣告是無效的
console.log(qq); // qq function
qq = 'Ray';
console.log(qq); // Ray
}

fn(qq);

但是這邊要注意一件事情,不管怎麼樣,函式內的提升並不會影響到參數的傳入只是會被重新賦予值而已。

參數傳入

除此之外附帶一提,當若參數傳入的數量不等於函式內的數量時,就會被用 undefined 取代概念就跟宣告變數不給予值是一樣的

1
2
3
4
5
function fn(qq, bb, cc) {
console.log(qq, bb, cc); // Ray, undefinedl, undefined
}

fn('Ray');

參數在傳入時也必須小心物件傳參考特性,當若你是傳入一整個物件時,也會保留原始物件傳參考特性

1
2
3
4
5
6
7
8
9
10
11
var obj = {
name: 'Ray',
};

function fn(a) {
a.name = 'QQ';
}

fn(obj);

console.log(obj.name); // QQ

但是如果是單純傳入物件中的單一屬性時,就不會發生物件傳參考問題

1
2
3
4
5
6
7
8
9
10
11
var obj = {
name: 'Ray',
};

function fn(a) {
a.name = 'QQ';
}

fn(obj.name);

console.log(obj.name); // Ray

因此許多 ESLint 規範都會建議你不要調整傳入的物件,避免你不小心修改到你不想修改的東西。

CallBack Function

函式除了傳入物件與純值之外,也可以傳入函式,而在此函式就可以是匿名函式

1
2
3
4
5
6
7
function functionA(fn) {
fn();
}

functionA(function() {
console.log('Ray');
})

這個方式就稱之為 CallBack Function,中文又稱回呼函式,因此只要你傳入的是一個函式表達式,那麼就可以被使用

1
2
3
4
5
6
7
8
9
function functionB(fn) {
console.log('Ray');
}

function functionA(fn) {
fn();
}

functionA(functionB);

參考文獻

Liker 讚賞 (拍手)

如果這一篇筆記文章對你有幫助,希望可以求點支持或 牡蠣 鼓勵 (ノД`)・゜・。

Liker 是一個按讚(拍手)的讚賞機制,每一篇文章最多可以按五下(拍手),按讚過程你是完全不用付費的(除非你想要每個月贊助我 :D),你只需要登入帳號就可以開始按讚。
而 Liker 會依據按讚數量分配獎金給創作者,所以如果你願意按個讚我會非常感謝你唷。

Google AD

撰寫一篇文章其實真的很花時間,如果你願意「關閉 Adblock (廣告阻擋器)」來支持我的話,我會非常感謝你 ヽ(・∀・)ノ