1、簡述
高階函式似乎是一種先進程式設計的的技術。然而,並不是。
高階函式其實就是將函式作為引數或者返回值的函式。其中作為引數的函式一般是回撥函式。
2、例子
(1)最簡單的例子
大家都熟悉陣列的sort方法。
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>高階函式</title>
</head>
<body>
<script type="text/javascript">
let arr = [1,2,4,3];
arr.sort((a,b)=>{return a-b})
console.log(arr)
</script>
</body>
</html>
sort方法的引數就是一個函式(回撥函式),這個回撥函式決定了如何比較陣列中的任意兩個元素。
Array的sort方法原始碼實現(使用了插入排序和快速排序):
function ArraySort(comparefn) { // 使用款速排序演算法 // 對於長度小於22的陣列,使用插入排序演算法 //判斷comparefn是不是一個函式 var custom_compare = IS_FUNCTION(comparefn); function Compare(x, y) { // 假設comparefn(若存在的話)是一致的比較函式。 // 如果不是,則假設假設comparefn函式是任意的(通過ECMA 15.4.4.11) if(x === y) return 0; if(custom_compare) { // 不要直接呼叫comparefn以避免暴露內建的全域性物件。. return comparefn.call(null, x, y); } x = ToString(x); y = ToString(y); if(x == y) return 0; else return x < y ? -1 : 1; }; //插入排序 function InsertionSort(a, from, to) { for(var i = from + 1; i < to; i++) { var element = a[i]; // Pre-convert the element to a string for comparison if we know // it will happen on each compare anyway. var key = (custom_compare || % _IsSmi(element)) ? element : ToString(element); // place element in a[from..i[ // binary search var min = from; var max = i; // The search interval is a[min..max[ while(min < max) { var mid = min + ((max - min) >> 1); var order = Compare(a[mid], key); if(order == 0) { min = max = mid; break; } if(order < 0) { min = mid + 1; } else { max = mid; } } // place element at position min==max. for(var j = i; j > min; j--) { a[j] = a[j - 1]; } a[min] = element; } } //快速排序 function QuickSort(a, from, to) { // 若陣列長度小於22的話,使用插入排序。 if(to - from <= 22) { InsertionSort(a, from, to); return; } var pivot_index = $floor($random() * (to - from)) + from; var pivot = a[pivot_index]; // Pre-convert the element to a string for comparison if we know // it will happen on each compare anyway. var pivot_key = (custom_compare || % _IsSmi(pivot)) ? pivot : ToString(pivot); // Issue 95: Keep the pivot element out of the comparisons to avoid // infinite recursion if comparefn(pivot, pivot) != 0. a[pivot_index] = a[from]; a[from] = pivot; var low_end = from; // Upper bound of the elements lower than pivot. var high_start = to; // Lower bound of the elements greater than pivot. // From low_end to i are elements equal to pivot. // From i to high_start are elements that haven't been compared yet. for(var i = from + 1; i < high_start;) { var element = a[i]; var order = Compare(element, pivot_key); if(order < 0) { a[i] = a[low_end]; a[low_end] = element; i++; low_end++; } else if(order > 0) { high_start--; a[i] = a[high_start]; a[high_start] = element; } else { // order == 0 i++; } } QuickSort(a, from, low_end); QuickSort(a, high_start, to); } var old_length = ToUint32(this.length); if(old_length < 2) return this; % RemoveArrayHoles(this); var length = ToUint32(this.length); // 將未定義的元素移動到陣列的末尾. for(var i = 0; i < length;) { if(IS_UNDEFINED(this[i])) { length--; this[i] = this[length]; this[length] = void 0; } else { i++; } } QuickSort(this, 0, length); //如果this是一個陣列,我們只改變了這個陣列的長度。 如果this不是陣列,則不允許設定此物件的長度,因為這可能會引入新的length屬性。 if(IS_ARRAY(this)) { this.length = old_length; } return this; }
(2)字元換大寫
實現一:
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>高階函式</title>
</head>
<body>
<script type="text/javascript">
let arr = ['abc', 'def'],
arrNew = [];
for(let i = 0; i < arr.length; i++) {
arrNew[i] = arr[i].toUpperCase()
}
console.log(arrNew)
</script>
</body>
</html>
實現二:
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>高階函式</title>
</head>
<body>
<script type="text/javascript">
let arr = ['abc', 'def'],
arrNew = [];
arrNew = arr.map(val => {
return val.toUpperCase()
})
console.log(arrNew)
</script>
</body>
</html>
(3)高階函式實現
若程式碼中出現重複或者類似的程式碼,就可以使用高階函式。如產生一個包含數字的字串:
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>高階函式</title>
</head>
<body>
<script type="text/javascript">
let digits = ''
for (let i=0;i<10;i++) {
digits += i
}
console.log(digits)
</script>
</body>
</html>
使用高階函式實現:
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>高階函式</title>
</head>
<body>
<script type="text/javascript">
let digits = ''
function buildString(n, callback) {
let val = '';
for(let i = 0; i < n; i++) {
val += callback(i)
}
return val
}
digits = buildString(10, i => {
return i
})
console.log(digits)
</script>
</body>
</html>