函數式編(Function Programming, FP) 是程式設計範式之一。
程式設計範式即程式設計規範,程式設計風格
我們常聽聽說的程式設計範式還有:
- 面向對象:典型的就是
語言,目前java
的超集javascript
也是走這條路線。也就是把事物抽象成程式世界中的類和對象,通過封裝、繼承和多态來示範事物之間的聯系。typescript
- 面向過程:典型的就是
語言。在面向過程程式設計中,問題被看成是一些列需要完成的任務,函數則用于完成這些任務,可以看成一步步更新打怪。C
而我們今天要讨論的程式設計範式 -- 函數式程式設計把事物和事物直接的聯系抽象到程式世界,強調的是函數的計算,對運算過程進行抽象。使用函數進行程式設計。
純函數
純函數 指相同的輸入永遠得到相同的輸出,而且沒有副作用。
如下:
slice
是純函數,
splice
就不是。
let arr = [1, 2, 3];
console.log(arr.slice(0,1)); // 1
console.log(arr.slice(0,1)); // 1
console.log(arr.slice(0,1)); // 1
let another_arr = [3, 4, 5];
console.log(another_arr.splice(0,1)); // 3
console.log(another_arr.splice(0,1)); // 4
console.log(another_arr.splice(0,1)); // 5
純函數是函數程式設計的重點。函數是函數程式設計的一等公民。
一等公民,指函數跟其他類型具有相同的地位,也就是說 可以當作令一個
function
的參數,也可以作為
function
的傳回值,也可以作為變量。
function
比如:
function demo(cb) {
cb()
}
function add(x) {
return function(y) {
return x + y
}
}
const val = () => 'jimmy';
聲明式程式設計
函數式程式設計屬于聲明式程式設計範式。
聲明式程式設計範式:會描述一些列的操作,但是并不會暴露他們是如何實作的或者資料流是如何傳遞的。
比如:
let arr = ['hello', 'world', '!']
// 指令式,暴露具體實作
for(let i = 0; i < arr.length; i++) {
arr[i] = arr[i].toUpperCase()
}
// 聲明式,隐藏細節
arr.map(str => str.toUpperCase())
引用透明
引用透明(Referential Transparency)指的是一個函數穿傳入相同的參數,不管運算多少次,永遠會得到相同的值,并且不對外部世界産生任何改變(上面我們已經提到過,就是不産生副作用)。
例子可以參考上面純函數的例子。
又比如:
function change_style() {
let dom = document.getElementById('demo');
dom.style.color = 'red';
}
// change_style 對外界産生的副作用,更改了 dom 的樣式
不可變性
不可變性,就是資料一旦建立後就不會再改變的,所有對不可變性的資料操作傳回的是另一個不可變性的資料。這好比操作
const
定義變量一樣。
又比如:
let obj = {
name: 'jimmy'
}
let person = obj;
person.name = 'Jimmy';
console.log(obj.name); // Jimmy
// 此時,對象 obj.name 資料已經發生了改變(可變)
let obj1 = {
name: 'jimmy'
}
let person1 = { ...obj, name: 'Jimmy'};
console.log(obj1.name); // jimmy
// 此時,對象 obj.name 資料沒發生變化(不可變)
- 純函數
- 函數是一等公民
- 聲明式程式設計
- 引用透明
- 不可變性
function throttle(fn) {
let canRun = true;
return function() {
if(!canRun) {
return;
}
canRun = false;
setTimeout(() => {
fn.call(this, arguments);
canRun = true;
}, 1000)
}
}