JavaScript函數語言程式設計
1:基本概念
函數語言程式設計是一種程式設計思維方式,並不是一些語法規則,對於複用性高的功能程式碼進行一定的函式封裝,實現了程式碼的高可複用性(主要目的)。
函數語言程式設計的特點:
-
函式是第一等公民,因為叫函數語言程式設計,因此函式的地位是最高的,也就是說比起變數函式的地位更高一點。
-
只用表示式而不用語句,表示式就是宣告式的意思,語句就是命令式的,儘量使用表示式或者是宣告式的程式碼來組織邏輯。
-
沒有副作用的程式碼,也叫做純函式或者在一些開發框架中也叫作純主鍵,純的意思是輸入一定那麼輸出也一定。
-
不修改狀態。
-
引用透明。
2:函式是一等公民
理解:函式在整個JavaScript程式碼裡面一般來講有四種,第一種叫做宣告函式、然後是表示式函式、匿名函式以及自執行函式。
為什麼函式是一等公民?
- 函式宣告優先順序高於變數宣告和函式表示式
console.log(getName); getName(); var getName; getName = 'Eric'; function getName(){ console.log('function getName'); } console.log(getName); //ƒ getName(){ console.log('function getName'); } // function getName // Eric
- 函式應用
//宣告函式 function getName(){ } //表示式函式(直接賦給一個變數) var getName = function(){ } //匿名函式(沒有名字) setTimeout(function(){ },1000); //自執行函式(IIFE) (function(){ })();
3:純函式
特點:
- 對於相同的輸入,永遠會得到相同的輸出
function getNumber(num){ return num + Math.random(); }
- 不改變輸入值
function getGirlGift(list){ // 輸入值改變 list = list.map(girl => { girl.gift = girl.age > 18 ? 'big' : 'small'; }); return list; }
- 不包含副作用(網路、I/O)
var array = \[1,2,3,4,5\]; array.slice(0,3); array.slice(0,3); // \[1, 2, 3\] // 改變原陣列 array.splice(0,3); array.splice(0,3); // \[4, 5\] //網路請求 asiox.get('https://www.xxxx.com').then(res => { }) //時間 function getDate(){ return new Date(); }
- Array函式舉例
以陣列為例,純與不純函式有哪些: //不純:呼叫陣列之後改變了原陣列。 array.push(); 陣列尾部插入 array.pop(); 刪除並返回陣列最後一個元素 array.unshift(); 陣列頭部插入 array.shift(); 刪除並返回陣列第一元素 array.splice(); 刪除元素,並向陣列新增元素 array.reverse(); 顛倒陣列元素的順序 array.sort(); 排序陣列元素 //陣列純函式:呼叫陣列的方法不改變原陣列。 array.slice(); 陣列中返回選定的元素 array.concat(); 連線陣列,併發揮新陣列 array.join(); 按分隔符連線陣列,返回字串
4:函式柯里化
定義:傳遞給函式的一部分引數來呼叫它,讓它返回一個函式去處理剩下的引數。
柯里化是把接受多個引數的函式變換成接受一個單一引數(最初函式的第一個引數)的函式,並且返回接受餘下的引數而且返回結果的新函式的技術。例如:
// 普通的add函式
function add(x, y) {
return x + y
}
add(1,2);
// 3
// 柯里化改編後
function addX(y) {
return function (x) {
return x + y;
}
}
addX(2)(1);
// 3
// 函式不純 \- 硬編碼 \- 依賴min引數
var min = 90;
var isWell = score => score > min;
// 柯里化改編
var min = 90;
var chekoLevel = baseLine => (score => score > baseLine);
var isWell = chekoLevel(90);
// isWell(90)
false
// isWell(940)
true
實際上就是把add函式的x,y兩個引數變成了先用一個函式接收x然後返回一個函式去處理y引數。現在思路應該就比較清晰了,就是隻傳遞給函式一部分引數來呼叫它,讓它返回一個函式去處理剩下的引數。
一種對引數的快取
-
用在一些區分環境的函式預快取
-
已獲取某些耗時操作結果快取
5:函式組合
在函數語言程式設計思想之前,出現過一個函式巢狀的現象,函式巢狀是一個函式的執行結果它是另外一個函式的入參,一般來講是兩層,但是兩層以上或者更多也是可能的。比如下面的程式碼,它的意思是function13的結果作為function2的入參,然後function2的結果又作為function1的入參。這樣的寫法不太好理解而且容易混亂,因此在這個基礎上,衍生了函數語言程式設計的另外一個思想,叫做函式組合。
函式組合是通過另外一個函式去組合巢狀函式,但是函式本身的巢狀關係,依賴關係是不會改變的。只不過是通過另外一個函式完成一個組裝。
- 函式巢狀
function1(function2(function13(x)));
- 函式組合
var compose = (function1, function2) => (x => function1(function2(x))); var function1 = param => param + 1; var function2 = param => param + 2; var final = compose(function1, function2); final(1); // 4
6:Point Free
不要命名轉瞬即逝的中間變數。
var getSplitWord = str => str.toUpperCase().split(' ');
//柯里化封裝
var toUpperCase = word => word.toUpperCase();
var split = x => str => str.split(x);
var getSplitWord = compose(split(' '), toUpperCase);
7:宣告式程式碼
var students = \[{
name: 'Eric',
score: 99,
},
{
name: 'Iven',
score: 59,
}
}\];
//命令式
const getWell =students => {
let result = \[\];
for (let i = 0; i < students.length; i++){
if (students\[i\].score >= 90){
result.push(students\[i\])
}
}
return result;
}
//宣告式
const getWell = students => return students.filler(student => students.score >= 90);
8:高階函式
把函式當引數,把傳入的函式做一個封裝。
function add(x,y,f){
return f(x) + f(y);
}
高階函式是對其他函式進行操作的函式,可以將它們作為引數或返回它們。 簡單來說,高階函式是一個函式,它接收函式作為引數或將函式作為輸出返回。
常見的高階函式有:
-
Array.map
var array = \[1,2,3\]; array.map(s => s + 1); // \[2, 3, 4\]
-
Array.sort(排序)
-
Array.filter(