CH3. 初探頭等函式 : 定義與引數


3-1 使用函式與否的差異為何?

物件具有某些特性

var ninja = {}; // 指派一個新物件給一個變數
ninjaArray.push({}); // 在陣列中新增一個物件
ninja.data = {}; // 指派新物件作為某個物件的屬性

function hide(ninja) {
    ninja.name = 'wayne';
}
hide({}); // 將新建立的物件作為引數傳遞給函式

function returnNewNinja() {
    return {}; // 從函式回傳一個新物件
}

var ninja = {};
ninja.name = 'wayne'; // 在物件上新增一個屬性

函式也具備同樣的特性

function ninjaFunction() {}
var ninja = {}; // 指派一個新函式給一個變數
ninjaArray.push({}); // 在陣列中新增一個函式
ninja.datat = {}; // 指派新函式作為某個物件的屬性

function hide(ninja) {
    ninja.name = 'wayne';
}
hide({}); // 將新建立的函式作為引數傳遞給函式

function returnNewNinja() {
    return {}; // 從函式回傳一個新函式
}

var ninja = {};
ninja.name = 'wayne'; // 對函式新增一個屬性

3.1.2 回呼函式 Callback functions

瀏覽器事件

document.body.addEventListener("mousemove", function() {
  var second = document.getElementById("second");
  addMessage(second, "Event: mousemove");
});

排序

var values = [0, 3, 2, 5, 7, 4, 8, 1];

values.sort(function(value1, value2){
  return value1 - value2;
});

JavaScript 最重要的特性之一,能夠在程式中的任何地方建立函式,因此能寫出更緊湊且更易於理解的程式碼,
此函式不需要被其他地方引用,可避免全域命名空間被不必要的命名所污染(例如 sort 的引數)

3.2 函式作為物件的有趣之處

儲存函式

var store = {
    nextId: 1,
    cache: {},
    add: function(fn) {
      if (!fn.id) {
        fn.id = this.nextId++;
        this.cache[fn.id] = fn;
        return true;
      }
    }
  };

function ninja(){}

assert(store.add(ninja), "Function was safely added.");
assert(!store.add(ninja), "But it was only added once.");

自我記憶函式

function isPrime(value){
  if (!isPrime.answers){
    isPrime.answers = {};
  }

  if (isPrime.answers[value] !== undefined) {
    return isPrime.answers[value];
  }

  var prime = value !== 1; // 1 is not a prime

  for (var i = 2; i < value; i++) {
    if (value % i === 0) {
      prime = false;
      break;
    }
  }
  return isPrime.answers[value] = prime;
}

assert(isPrime(5), "5 is prime!" );
assert(isPrime.answers[5], "The answer was cached!" );

可應用在數學運算,減少重複的計算。
但任何一種的暫存方式,都是用空間換取時間。


後來看 JavaScript 設計模式,發現單體模式 ( singleton ) 有使用到這個特性。

儲存在靜態屬性中的實體

function Universe() {
    // 判斷是否已有現有的實體
    if (typeof Universe.instance === "object") {
        return Universe.instance;
    }

    this.startTime = 0;
    this.bang = "Big";

    // 快取
    Universe.instance = this;
}

var uni1 = new Universe();
var uni2 = new Universe(); // uni2 會得到相同的 instance

缺點,可以直接存取 Universe.instance ,有機會被異動
ref: 單體模式 ( Singleton )

3.3 定義函式

定義函式的方式:

  • 函式宣告 function foo() {}
  • 函式表達式 var foo = function() {}
  • 箭頭函式 item => item * item
  • 函式建構式 new Function('a', 'b', 'return a + b')
  • 生成器 function* my myGen() { yield 1; }

3.3.1 立即函式 (IIFE: immediately invoked function expression)

IIFE 可以在 JavaScript 中模擬出模組的功能

(function(){console.log('Hi')})(); // 'Hi'

需要外面的括號是因為語法的關係,要讓 JavaScript 能夠輕易區分函式宣告式函式表達式
function(){}(); 會拋出錯誤 Function statements require a function name ,因為函式宣告式需要定義函式名稱。
因此放在括號內,通知 JavaScript 解析器它處理的是一個表達式,而不是一個敘述句。

// 其他具有同樣概念的表達式
// 使用一元運算子,告訴 JavaScript 引擎它在處理的是一個表達式而不是敘述句
+function(){console.log('Hi')}(); // 'Hi'
-function(){console.log('Hi')}(); // 'Hi'
*function(){console.log('Hi')}(); // 'Hi'
!function(){console.log('Hi')}(); // 'Hi'

3.4 引數 ( argument ) 與函式參數 ( parameter )

原文:

A parameter is a variable that we list as part of a function definition.
An argument is a value that we pass to the function when we invoke it.

  • 當提供的引數比參數多時,並不會造成錯誤
  • 但是引數比參數少時,沒有相對應引數的參數會被設為 undefined

看到這章節,才發現以前不管是引數或是參數,我都會用變數來描述,以後為了避免誤會,會修正自己的用詞。

3.4.1 不定參數 ( rest parameter ) - ES6

function multiMax (first, ...restParameter) {
    //  ...restParameter 是個陣列
    console.log(first); // 3
    console.log(restParameter); // [4, 5, 6]
}

multiMax(3, 4 ,5 ,6); // ...restParameter -> [4, 5, 6]
function multiMax (...restParameter) {
    console.log(restParameter);
}

multiMax(3, 4 ,5 ,6); // ...restParameter -> [3, 4, 5, 6]

只有最後一個參數可以是不定參數,否則會得到 SyntaxError: parameter after rest parameter

3.4.2 預設參數 ( default parameter ) - ES6

ES6 以前的實作參數預設值的方式

function performAction(ninja, action){
     action = typeof action === "undefined" ? "skulking" : action;
     return ninja + " " + action;
  }

ES6 可以在預設參數置入表達式

function performAction(
    ninja, 
    action = "skulking", 
  message = ninja + " " + action // 表達式
) {
  return message;
}

此寫法並不會增加可讀性,因為要去看函式定義才知道有預設值,
書中建議適度使用,可作為避免空值 ( null ) 的手段或設定函式行為的 flag

#javascript #function







你可能感興趣的文章

Firebase iOS (3) 登入主頁完成篇

Firebase iOS (3) 登入主頁完成篇

金魚系列、RWD (下) - RWD 選單

金魚系列、RWD (下) - RWD 選單

深入探討 redux middleware

深入探討 redux middleware






留言討論