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