wordpress 批量圖片海會網(wǎng)絡做的網(wǎng)站怎么做優(yōu)化
介紹:
函數(shù)式編程(FP)是一種編程范式,這意味著一種基于一些原則來思考軟件構建的方法,比如 純函數(shù)、不可變性、一等與高階函數(shù)、函數(shù)組合、閉包、聲明式編程、遞歸、引用透明性、柯里化 和 部分應用。
當這些原則有效地應用到 JavaScript 中時,可以使得代碼更加模塊化、可維護、健壯、易于理解、可測試,并且能夠優(yōu)雅地處理復雜的問題。
這篇文章看起來可能有點長,但不會那么理論化。
讓我們開始逐一實驗吧:
1. 純函數(shù):
兩條規(guī)則:
- 給定相同的輸入,總是返回相同的結果。
- 不產(chǎn)生副作用。
用處: 容易重構,使代碼更具靈活性和適應性。
例子 1:
// 不純的函數(shù)。
let a = 4;
const multiplyNumbers = (b) => a *= b;multiplyNumbers(3);
console.log(a); // 第一次調用:12
> 12
multiplyNumbers(3);
console.log(a); // 第二次調用:36
> 36// 修改了外部變量,所以不是純函數(shù)。
// 純函數(shù)版本。
const multiplyNumbers = (x,y) => x * y;multiplyNumbers(2, 3);
> 6
例子 2:
// 不純的函數(shù)。
addNumberarr = (arr, num) => {
arr.push(num);
};
const testArr = [1,2,3];
addNumberarr(testArr, 4);console.log(testArr);
> [1, 2, 3, 4]// 修改了輸入數(shù)組,所以不是純函數(shù)。
// 上面的純函數(shù)版本。
addNumberarr = (arr, num) => {
return [...arr, num];
};
const testArr = [1,2,3];
addNumberarr(testArr, 4);
> [1, 2, 3, 4]
JS 內置的純函數(shù):
arr.reduce()
arr.map()
arr.filter()
arr.concat()
arr.slice()
arr.each()
arr.every()
... - 擴展語法
JS 內置的非純函數(shù):
arr.splice()
arr.push()
arr.sort()
Math.random()
2. 不可變性:
一旦創(chuàng)建就不能改變狀態(tài)的對象。
一個簡單的例子就是使用 slice 方法來幫助你輕松理解它的含義。
const arr = [1,2,3,4];const slicedArray = arr.slice(1,2);slicedArray
> [2]arr
> [1, 2, 3, 4]
如果你看上面的例子,slice 并沒有改變原始數(shù)組 arr。而下面的例子則不同:
const arr = [1,2,3,4];arr.push(5);
> 5arr
> [1, 2, 3, 4, 5]
原始數(shù)組 arr 被修改了。這并不是說我們不應該使用 push,但是在大多數(shù)情況下我們可以避免這種情況。一個簡單的例子是:
const arr = [1,2,3,4];const newArr = [...arr, 5];arr
> [1, 2, 3, 4]newArr
> [1, 2, 3, 4, 5]
上面的所有都是簡單例子,可能不會造成任何問題。但是,如果我們在整個文件中盡可能多地修改同一個對象,就會帶來許多問題。因為我們需要跟蹤這個對象被修改了多少次以及以何種方式被修改。
為了解決這個問題,我們需要避免修改對象。
3. 一等函數(shù)
一等函數(shù)是指把函數(shù)當作一等公民的概念,意味著它們被視為常規(guī)變量或值。這讓函數(shù)可以像字符串或數(shù)字等其他數(shù)據(jù)類型一樣被操作和使用。這允許函數(shù)作為參數(shù)傳遞給其他函數(shù),從其他函數(shù)返回值,以及被賦值給變量。JavaScript 支持這一點。
它打開了強大的編程技術的大門,比如高階函數(shù)、函數(shù)組合,以及抽象的創(chuàng)建。
4. 高階函數(shù):
一個函數(shù)可以接受另一個函數(shù)作為參數(shù)或者返回一個函數(shù)作為結果,這樣的函數(shù)被稱為高階函數(shù)。
- 返回一個函數(shù)的函數(shù)
const higherOrderFunc = function() {return function() {return 12;}
}// 返回下面的函數(shù),所以它是高階函數(shù)。
higherOrderFunc();
> ? () {return 12;}higherOrderFunc()();
> 12
- 接受一個函數(shù)作為參數(shù)的函數(shù)
const testFunc = function(x) {return x + 12;
}// 接受函數(shù)作為參數(shù)。
const higherOrderFunc = function(testFunc) {return testFunc(8);
}higherOrderFunc(testFunc);
> 20
例子 1:
function calculate(operation, numbers) {return operation(numbers);
}function addition(numbers) {let sum = 0;for (const number of numbers) {sum+=number;}return sum;
}function multiply(numbers) {let sum = 1;for (const number of numbers) {sum*=number;}return sum;
}const numbers = [1,2,3,4,5];
console.log(calculate(addition, numbers));
> 15console.log(calculate(multiply, numbers));
> 120// calculate(multiply, numbers) - 傳遞函數(shù)作為參數(shù)時不加括號。
高階函數(shù)的好處:
減少代碼重復
單一職責
在 JavaScript 中,函數(shù)可以接受原始類型或對象作為參數(shù)并返回相同類型,稱為一階函數(shù)。
JS 內置的高階函數(shù)有:
arr.reduce(), arr.forEach(), arr.filter(), arr.map()
5. 函數(shù)組合:
這是一種方法,其中將一個函數(shù)的結果傳給下一個函數(shù)。
const add = (x, y) => x+y;const subtract = (x) => x-4;const multiply = (x) => x * 8;// add 的結果傳給 subtract,其結果再傳給 multiply。
const result = multiply(subtract(add(2, 3)));result;
> 8
看起來很清晰,但如果我們要一個接一個地調用更多函數(shù)會怎么樣呢?讓我們試試更干凈的方法。
const compose = (...functions) => x => functions.reduceRight((total, f) => f(total), x);const add = x => x+2;const subtract = x => x-1;const multiply = x => x * 8;compose(multiply, subtract, add)(2);
> 24
我們也可以使用 reduce 來實現(xiàn):
const pipe = (...functions) => x => functions.reduce((total, f) => f(total), x);const add = x => x+2;const subtract = x => x-1;const multiply = x => x * 8;pipe(add, subtract, multiply)(2);
> 24
pipe - 從左到右執(zhí)行。
compose - 從右到左執(zhí)行。
6. 聲明式編程:
聲明式: 告訴 做什么
命令式: 告訴 怎么做
例子: 找出部門為 ‘justCode’ 的員工及其工資總和。
命令式風格:
const employees = [
{id: 1, name: 'james', dept: 'admin', salary: 10000},
{id: 1, name: 'Tom', dept: 'finance', salary: 10000},
{id: 1, name: 'peter', dept: 'justCode', salary: 12500},
{id: 1, name: 'tunner', dept: 'justCode', salary: 14500},
];const justCodeDept = [];// 根據(jù)部門名稱篩選員工。
for (let i=0; i<employees.length; i++) {if (employees[i].dept === 'justCode') {justCodeDept.push(employees[i]);}
}// 計算 justCodeDept 員工的工資總和。
let summation = 0;
for (j = 0; j<justCodeDept.length; j++) {summation = summation + justCodeDept[j].salary;
}console.log(summation);
聲明式風格:
const employees = [
{id: 1, name: 'james', dept: 'admin', salary: 10000},
{id: 1, name: 'Tom', dept: 'finance', salary: 10000},
{id: 1, name: 'peter', dept: 'justCode', salary: 12500},
{id: 1, name: 'tunner', dept: 'justCode', salary: 14500},
];console.log(employees.filter(item => item.dept === 'justCode').reduce(((previousValue, currentValue) => previousValue += currentValue.salary), 0));
7. 柯里化:
將接收多個參數(shù)的函數(shù)拆分成一系列函數(shù),每個函數(shù)只接收單個參數(shù)。
例子 1:
通常我們寫:
function addition(x, y, z) {return x + y + z;
}addition(1, 2, 3);
> 6
柯里化版本:
function addition(x) {return function addY(y) {return function addZ(z) {return x + y + z;}}
}addition(1)(2)(3);
> 6
使用箭頭函數(shù):
addition = (x) => (y) => (z) => x + y + z;addition(1)(2)(3);
> 6
例子 2:
function formWelcomNote(name) {name = `Hello ${name}, `;return function(location) {location = `Welcome to ${location},`;return function(section) {return `${name}${location} Please visit ${section} section`}}
}formWelcomNote('Yester')('VK Just Code Articles')('JS Articles');
> 'Hello Yester, Welcome to VK Just Code Articles, Please visit JS Articles section'
我們也可以這樣寫:
formWelcomNote = (name) => {name = `Hello ${name}, `;return (location) => {location = `Welcome to ${location},`;return (section) => {return `${name}${location} Please visit ${section} section`}}
}formWelcomNote('Yester')('VK Just Code Articles')('JS Articles');
> 'Hello Yester, Welcome to VK Just Code Articles, Please visit JS Articles section'
例子 3:
function calculation(fn) {switch (fn) {case 'add': return (a, b) => a + b;case 'sub': return (a, b) => a - b;case 'mul': return (a, b) => a * b;case 'div': return (a, b) => a / b;}
}
console.log(calculation('mul')(4, 2));
8. 部分應用:
你為一個函數(shù)固定一定數(shù)量的參數(shù),并生成一個新的帶有較少參數(shù)的函數(shù)。這個新函數(shù)可以在稍后的時間用剩下的參數(shù)來調用。部分應用有助于創(chuàng)建更加專業(yè)和可重用的函數(shù)。
例子:
function add(a, b) {return a + b;
}// 部分應用第一個參數(shù)
const add2 = add.bind(null, 2);console.log(add2(5)); // 輸出:7 (2 + 5)
console.log(add2(8)); // 輸出:10 (2 + 8)
9. 引用透明性:
JavaScript 中的一個表達式可以用它的值來替代,這種特性叫做引用透明性。
const add = (x, y) => x + y;const multiply = (x) => x * 4;// add (3, 4) 可以被替換為 7 —— 引用透明性。multiply(add(3, 4));
> 28multiply(add(3, 4));
> 28
const arr = [];
const add = (x, y) => {const addition = x + y;arr.push(addition);return addition;
}const multiply = (x) => x * 4;// 在這里,我們不能用 7 替換 add(3, 4),因為它會影響程序邏輯。
multiply(add(3, 4));
> 28multiply(add(3, 4));
> 28
10. 閉包:
閉包讓你可以從內部函數(shù)訪問外部函數(shù)的作用域。
function outer() {const name = 'test';function inner() {// 'name' 從外部函數(shù)可以訪問到內部函數(shù)中console.log(name);}inner();
}
outer();> test
function outerAdd(x) {return function(y) {return x + y;};
}const outer12 = outerAdd(12); // x 為 12.
const outer14 = outerAdd(14); // x 為 14.const outer12Result = outer12(12); // y 為 12.
console.log(outer12Result);
> 24const outer14Result = outer14(14); // y 為 14.
console.log(outer14Result);
> 28
或者,你也可以像下面這樣使用箭頭函數(shù):
outerAdd = x => y => x + y;const outer12 = outerAdd(12);
const outer14 = outerAdd(14);const outer12Result = outer12(12);
console.log(outer12Result);
> 24const outer14Result = outer14(14);
console.log(outer14Result);
> 28
使用閉包的計數(shù)器示例:
function outer() {let counter = 0;return function inner() {counter += 1;return counter;}
}
const out = outer();console.log(out());
console.log(out());
console.log(out());> 1
> 2
> 3
11. 遞歸:
遞歸是一種編程技巧,在其中函數(shù)通過自我調用來解決問題。
例子:
function factorial(n) {if (n === 0 || n === 1) {return 1;} else {return n * factorial(n - 1);}
}console.log(factorial(5)); // 輸出:120 (5 * 4 * 3 * 2 * 1)
console.log(factorial(0)); // 輸出:1 (按定義)
在這個例子中,factorial 函數(shù)計算給定數(shù) n 的階乘。它使用了 n === 0 和 n === 1 的基本情況,階乘定義為 1。對于其它任何值的 n,函數(shù)遞歸地調用自身,并將結果乘以 n。
當你調用 factorial(5) 時,遞歸調用序列如下所示:
factorial(5)-> 5 * factorial(4)-> 4 * factorial(3)-> 3 * factorial(2)-> 2 * factorial(1)-> 1<- 2 * 1 = 2<- 3 * 2 = 6<- 4 * 6 = 24<- 5 * 24 = 120
如果有任何概念上的例子需要補充,請隨時評論。
希望通過今天這篇文章,讓你對JS中的函數(shù)式編程有了更好的理解。并且可以在日常的開發(fā)過程中進行靈活應用,以提高開發(fā)效率。