Yakim shu Hi, 這是我擴充腦內海馬體的地方。

[第二週] 基礎 JavaScript - 03 函式 Function

參數 Parameter & 引數 Argument

function fun1 (a, b) {
    return a+b;
}
var c = 10;
var d = 20;
console.log( fun1(c,d) );

Function 參數也可以丟入 Function

fun2() 也可以當作引數傳入fun1() 當作參數

以下例子中,fun1() 的參數 newFunction 其實傳入的就是 fun2()

function fun1(i, newFunction) { // newFunction 為 fun1() 的參數
    return i + newFunction;
}
function fun2(x) {
    return x * 2;
}
console.log(fun1(5, fun2(10))); // fun2() 為 fun1() 的引數

以下例子將陣列 [1, 2, 3] 傳入 transform(),目的是回傳兩倍 & 三倍的陣列值。

function transform(arr, transformFunction) {
    var result = [];
    for (var i=0; i<arr.length; i++) {
        result.push(transformFunction(arr[i]));
    }
    return result;
}
function double(x) {
    return x*2;
}

function triple(x) {
    return x*3;
}
console.log(transform([1,2,3], double)); // [2, 4, 6]
console.log(transform([1,2,3], triple)); // [3, 6, 9]

依照上面的例子,也可以將函式 double()triple() 改寫成 匿名函式 Anonymous Function (函式內容一樣,只是沒有名字)

function transform(arr, transformFunction) {
    var result = [];
    for (var i=0; i<arr.length; i++) {
        result.push(transformFunction(arr[i]));
    }
    return result;
}
console.log(transform([1,2,3], function(x){ return x*2 })); // [2, 4, 6]
console.log(transform([1,2,3], function(x){ return x*3 })); // [3, 6, 9]

有關 Function 的宣告方式其實還有另一種,更詳細的可以參考以前筆記:Javascript大全 - 06 函式(一) 函式的定義方法,裡面有個經典案例去說明 JavaScript 對於不同的宣告方式會造成的不同編譯順序結果


到底傳什麼? Pass by (__) ?

又回到那個 pass by value 還是 pass by reference 還是 pass by address 還是 pass by sharing…無窮迴圈。 這大概是每隔一陣子就要複習一次,陷入漫長的查資料地獄,發現每個人說得好像都有點道理,開始進入越查越不懂的恐怖循環裡。

而 Huli 分享了他之前研究此問題的過程,連結在此:深入探討 JavaScript 中的參數傳遞:call by value 還是 reference?

幸好之前有留下 CS50 對 C 語言中指標的筆記,所以那篇文章我居然看得懂(開心)!推薦大家認真看完,文章也說明了此問題在其他語言( Java, C )的情形,我甚至有點像坐在榕樹下聽說書人講故事的感覺 (?),我直接引用結尾的一斷話:

別忘了,重點其實不在這個,而是搞清楚到底參數在操作的時候會有怎樣的行為。你要知道 JavaScript 傳 object 進去的時候,可以更改原本物件的值,但重新賦值並不會影響到外部的 object。只要知道這一點,其他的我覺得都沒那麼重要了。

看到這段話有「啊~我得到救贖了」的感覺,所以我決定不再去追根究底名詞背後的定義是什麼,我想我只要了解其中的行為,比該如何定義此行為還重要。

概念有點像之前看到一個網路上蠻有名的昆蟲教授,他說:「 要怎樣才算是瞭解一個昆蟲呢?講得出他的中英文學名、知道介門綱目科屬種分在哪一類?還是說得出他的生物特性、了解什麼環境或因素會引發什麼特殊行為。 」( 原文找不到,其實應該不是這麼說的,我只是憑印象說明 )

總之直接看 code

pass by value 傳「值的拷貝」 ( 無庸置疑 )

原始型別 numstringboolean 都是傳值 pass by value,原來的 num1num2 並沒有被更改。

function swap (a, b){
    var temp = a;
    a = b;
    b = temp;
}
var num1 = 10;
var num2 = 5;
swap(num1, num2);
console.log(num1, num2); // 印出 10, 5

pass by sharing 傳「值的記憶體位置 」( 待討論,不是這裡的重點 )

而物件 object 則是傳分享 pass by sharing,原來的 obj1 被更改到了

function swap (obj){
    var temp = obj.a;
    obj.a = obj.b;
    obj.b = temp;
}
var obj1 = {
    a: 10,
    b: 5
}
swap(obj1);
console.log(obj1); // 印出 { a: 5, b:10 }

而又如果物件 object 本身被重新賦值,原來的 obj1不會收到影響。

function double(obj) {
    obj = {
        a: obj.a * 2
    }
}
var obj1 = { a: 10 };
double(obj1);
console.log(obj1); // 印出 { a: 10 }

內建函式

不同的程式語言總會有些自己的內建函式,目的在於簡化一些常用的功能,總之就是有人貼心造好的輪子,就不用再自己造了。

常用的數學相關函式

參考資料:

字串、數字間互相轉換

字串轉數字:

console.log(parseInt('50', 10)) // 50,10 代表 10 進位
console.log(Number('50')) // 50

數字轉字串:

var num = 10;
console.log(num.toString());
console.log(num+'');

常用的字串相關函式

var name = 'Yakim';
console.log(name.toUpperCase()); // Upper:  YAKIM
console.log(name.toLowerCase()); // Lower:  yakim
console.log(name.charCodeAt(0)); // code of Y:  89
console.log(name.charCodeAt(1)); // code of a:  97
console.log(String.fromCharCode(97)); // char of 97: a

var name2 = 'Yakim, hahahahaha';
console.log(name2.replace('ha', 'yo')); // Yakim, yohahahaha
// 注意:前面的引數類型不是字串,不用加 ''
console.log(name2.replace(/ha/g, 'yo')); // Yakim, yoyoyoyoyo
console.log(name2.split(',')); // [ 'Yakim', ' hahahahaha' ]

var name3 = '      Yakim   ';
console.log(name3.trim());  // Yakim

字串、陣列間互相轉換

字串轉陣列:

陣列轉字串:


常用的陣列相關函式

這部分先偷懶拿以前筆記來看,不然進度太慢、我要開天窗了啊啊啊啊

重點在於不同函式之間,有會改到原本陣列不會改到原本陣列、而回傳一個新陣列或其他變數類型的差別,通常是在於 回傳值也是陣列的情況下,就很有可能會改到陣列本身,聽起來也很合理,因為既然是要對陣列做改變,就直接在陣列本身做操作麻!( 說了通常是因為有例外,例如: slice()concat()

想要看更詳細的資訊,可以上 MDN - Array 裡面有超詳細的列表:


( 以上內容大部分是 程式導師實驗計畫第三期 的學習筆記,如有錯誤歡迎糾正,非常感謝 🤓 )