JS 中的 function & Arrow function 整理

  • JS 有時候會被叫成 functional programming language, 因為 JS 的核心之一就是 function。
  • function 的 ( ) 裡頭可以放參數(parameter) ,function 的變數,當要使用這個 function 時,會在參數裡頭放我們拿到的值會結果,這個時候放進去的值就會是 Argument(the actual value of this variable that gets passed to function)。所以當我們說 我們要 call a function 的意思就是寫出那個 function 名,然後可把 arguments 丟進去。
  • 宣告 function 要注意的幾點事項:
    1.function 名稱
    – 可以是英文字、數字或是 _ 或是 $ 組成的
    – 不能數字開頭
    – 不能夠有空格或是其他符號(分號逗號之類)
    – function 也可以不要有名稱(Anonymous function)
  • function 裡頭的 return 只能回傳一個,可以是 string、數字或 Boolean 等
  • function 要召喚(call)才有用!!!(我每次寫完就忘記召喚它 T_T 或是寫了一堆根本不會用到的 function)
var alertRandom = function () {
var randomNumber = Math.floor(Math.random() * 6 ) + 1;
alert(randomNumber);
};
alertRandom( ); // 在這邊才有 call 它

傳統 function 寫法 & Arrow function 寫法

Arrow function 沒有參數時要加上空括號

在 Arrow function 中如果只是要回傳某個值,可以省略 return

只有一個參數不需要使用括號,兩個以上參數要使用括號

箭頭函數當中的 this 是定義時的對象,而不是使用時的對象

ㄧ、Arrow function 沒有參數時要加上空括號:

//一般寫法
Function greeting(){
console.log(“yo”);
}
greeting();

// Arrow function 寫法 (沒參數時加空括號)
var greeting = ( ) =>{
console.log(“yo”);
}

greeting();

二、在 Arrow function 中如果只是要回傳某個值,可以省略 return:

//一般寫法
var greeting = function (){
return ”yo!”;
}

console.log(greeting()); 
// Arrow function 寫法 (省略 return)
greeting = ( ) => “yo!”;
console.log(greeting());

三、只有一個參數不需要使用括號,兩個以上參數要使用括號:

範例:一個參數時

//一般寫法
var greeting = function(person){
return “Hello” + person;
}
console.log(greeting(“Annie”));
// Arrow function 寫法 (一個參數時不用使用括號)
Var greeting = person => “Hello” + person;
console.log(greeting(“Annie”));

範例:兩個以上參數時

//一般寫法
var add = function(a, b){
return a+b;
}
console.log(add(3,5)); // 8
// Arrow function 寫法 (兩個以上參數要使用括號)
var add = (a,b) => a+b;
console.log(add(3,5)); // 8

四、箭頭函數當中的 this 是「定義時」的對象,而不是「使用時」的對象

範例ㄧ:使用 addEventListener

假設有一個 button,我們用 JS 要抓到這個 button,點擊它時要做事。

var button = document.querySelector(‘button’);
// 一般寫法
var fn = function(){
// 建立 function 時 this 指 Window
console.log(this.constructor.name) // 執行 function 時 this 指 HTMLButtonElement
button.addEventListener(‘click’, fn_arr);
//Arrow function 寫法
var fn_arr = () => {
// 建立 function 時 this 指 Window
console.log(this.constructor.name) // 執行 function 時 this 指 Window
};

一開始建立 function 的時候 this 所指稱的都是 window 這個物件,然而,如果是使用傳統的寫法,在觸發這個事件時所指稱的對象會從原本的 window 變成 HTMLButtonElement;若使用的是箭頭函式,則會固定所指稱的對象,因此 this 依然指稱的是 window 這個物件。

範例二:setTimeout & call

// 原本的 function
let fn = function(){
console.log(this.constructor.name); // Object(data)
setTimeout(function(){
console.log(this.constructor.name) // Window
},100);
}
// 箭頭函式 Arrow function
let fn_arr = function(){
console.log(this.constructor.name); // Object(data)
setTimeout(() => {
console.log(this.constructor.name) // Object(data)
},100);
}

let id = 21;

let data = {
id: 21
}

fn.call(data);
fn_arr.call(data);

setTimeout
setTimeout 執行的時間會在整個 JS execution context 都被執行完後才會執行,因此函式建立的時間和實際執行的時間是不同的,因此這也創造了兩個不同時間點的 this 所指稱的對象。

call
在 call 當中,我們會帶入後面所指定的物件當作所指稱的 this 對象
this.constructor.name:這樣子的寫法只是避免在回傳出物件的時候把整個物件內容給傳出來,而是指示傳出該物件的名稱。

因為有用 call(data) 的緣故,因此不論是使用傳統函式寫法(fn)或箭頭函式(fn_arr)時,在一開始函式裡面的 this 都指稱的是 data 這個物件。

然而不同的地方會在執行 setTimeout 中的函式:

使用傳統函式,使用 fn.call(data) 時,因為它執行的時間點是在整個 JS execution context 執行完才執行,而當時的環境會變成是 global environment,因此使用傳統函式時,這個 this 指稱的對象會轉變成 window object 。

使用 Arrow function,這個 this 所指稱的對象則不會改變,依然是 data 這個 object。

function & conditional statement

範例一:假設要偵測有沒有在一個 input 輸入 email

//先判斷是否是空值
function isEmailEmpty(){
var field = document.getElementById(‘email’); //先在 function 裡宣告好變數

if (field.value === ‘ ‘){
return true;
 } else {
return false;
}
} 

// 召喚這個判斷 Email 欄位是否是空值的 function,如果是空值,要...
var fieldTest = isEmailEmpty();
if(fieldTest === true){
alert(‘Please provide your email address.’);
}

function & return

function noAlert(){
return 5;
alert(“This won’t appear!”);
}

noAlert(); // 會回傳 5
alert(“This will appear!”); // 出現 This will appear

//The rest of the lines after return are not reachable.
//return exits a function and sends a value back to the spot in the program where the function was called

In a function, if you got a lot of return

Yes, but only one ever runs. Usually you’ll find multiple return statements within different branches of conditional statements.

另一個範例:

function getYear() {
var year = new Date().getFullYear();
return year;
}

var yearToday = getYear();
//這邊在做的事情是把 function return 的 year 存到 yearToday 這個變數

function 參數

可以控制或是丟新的東西進去這個 function:

Function getRandomNumber( upper ){
var randomNumber = Math.floor( Math.random( ) * upper ) + 1;
return randomNumber;
}
console.log(getRandomNumber(6));
//這樣 upper 的值就會是 6,這樣只是 function returns a number。所以,要看 results 必須要用 console.log

Function 可以放多個參數 (parameters)
function getArea(width, length, unit){
var area = width * length
return area + “ “ + unit ;
}
console.log(getArea(10, 20, ‘sq ft’)); // 會得到 200 sq ft
  • You can pass any number of arguments you want to a function ( But past a certain point gets a little difficult to manage) → for example 一次放 12 個 arguments、12 個 parameter to a function
  • 所以其實把 Array 、 Objects 丟到 function 裡是比較有效率的方式

function scope

假設在不同的 function 中用了同樣的變數名稱 width,是不會影響的,因為在 function 裡的變數只會在 function 裡作用。只有全域變數(function 外的)可以共用。

一、在 function 裡頭的變數宣告要用 var,如果不這麼做,就會去找外面的同樣名稱的全域變數

二、在不同 function 裡頭用同樣名稱的變數是 ok 的 (用 var)

範例一:

//scope of the function
function greeting(){
var person = ‘Annie’;
alert(person);
}

//scope outside of the function
var person = ‘George’;
greeting(); // Annie
alert(person); // George
greeting(); // Annie

**Its a bad idea to access global variables in a function -> It makes tracking down errors harder and makes functions dependent on global variables in other parts of a script

範例二:找 randomNumber

function getRandomNumber( lower, upper ){
// argument must be number ,所以在 console 前要先判斷
 if( isNaN(lower) || isNaN(upper)){
 throw new Error(‘error message’);
 }

 return Math.floor(Math.random() * (upper — lower + 1)) + lower;
 
}

console.log( getRandomNumber( ‘nine’, 24) ); //會出現 isNaN(‘nine’)
console.log( getRandomNumber( 1, 100) );