淺談JavaScript編程過程Function函數(shù)的幾種編程風(fēng)格
想了解更多關(guān)于開源的內(nèi)容,請?jiān)L問:
聲明
JavaScript編程過程中函數(shù)是一個(gè)很有趣的點(diǎn),JavaScript的函數(shù)與其他如:C、Java等語言有很大區(qū)別。對于從別的編程語言轉(zhuǎn)來的同學(xué)可能會存在一定的“坑”,如function函數(shù)與=>函數(shù)的區(qū)別。function函數(shù)this關(guān)鍵字的占用等。
在下文的案例中可能會使用這些知識,但我因?yàn)槠拗茖⒉粫@些語法進(jìn)行討論,只討論不同編碼方式的風(fēng)格問題。
測試環(huán)境申明
測試工具:DevEco Studio 3.1.1 Release 構(gòu)建版本:3.1.0.501
測試平臺:HarmonyOS Api9 x86 虛擬機(jī)
測試語言:ArkTS(只測試JavaScript語法部分)
簡介
因?yàn)镴avaScript編程風(fēng)格的靈活性。在一個(gè)簡單的求和函數(shù)、在JavaScript中可以使用很多不同的風(fēng)格表示。
小編將會以函數(shù)式編程、面向?qū)ο缶幊?、面向?qū)ο箧準(zhǔn)骄幊?、申明式編程等多個(gè)不同的方式表示出來。
以下代碼僅作為拋磚引玉的效果,不代表實(shí)際開發(fā)代碼,也不代表當(dāng)下所有的編碼風(fēng)格,小編只談?wù)撐伊私獾膸追N。在實(shí)際開發(fā)過程中每一種編碼風(fēng)格也會存在更多的細(xì)分風(fēng)格。
過程式編程
代碼
// 過程式編程
function add(...is: number[]) {
// 總和
let sum = 0;
// 求和
for (let index = 0; index < is.length; index++)
sum += is[index];
// 返回總和
return sum;
}
/**
* 使用樣例
* console.log(add(11, 22, 33));
*/
解讀
過程式編程是最簡單粗暴直接的編程方式,在所有主流編程語言中都支持使用過程式編程。
過程式編程往往需要編程者擁有過硬的編程素養(yǎng)與對業(yè)務(wù)的深刻理解才可以保證代碼的持續(xù)性的可維護(hù)性、可擴(kuò)展性。
在業(yè)務(wù)不確定、實(shí)現(xiàn)邏輯經(jīng)常變化、實(shí)現(xiàn)方案不穩(wěn)定的部分不建議使用這種編碼風(fēng)格,因?yàn)樗苋菀讓?dǎo)致代碼失控。
但是在算法實(shí)現(xiàn)上,筆者強(qiáng)烈建議各位使用這種編碼風(fēng)格。它簡單可靠,可以節(jié)約編程者的許多心智。
柯里化編程
代碼
// 自動(dòng)柯里化機(jī),可以自動(dòng)把函數(shù)轉(zhuǎn)化為柯里化風(fēng)格。
function curry(fn) {
return function curried(...args) {
if (args.length >= fn.length) {
return fn.apply(this, args);
} else {
return function (...nextArgs) {
return curried.apply(this, args.concat(nextArgs));
}
}
}
}
// 獲得轉(zhuǎn)化后的函數(shù)
export const curriedAdd = curry(add2);
/**
* 使用樣例
* console.log(curriedAdd(1)(2)); // 3
* console.log(curriedAdd(1, 2)); // 3
* console.log(curriedAdd(1)(2, 3)); // 3
*/
解讀
柯里化編程有一個(gè)有特色的地方是函數(shù)的連續(xù)嵌套,這是前端開發(fā)非常熱門的一種編程方式。但小編極力反對這種編程方式具體原因有一下幾點(diǎn):
- 柯里化編程雖然確實(shí)提高了開發(fā)的靈活性,但是它也降低了函數(shù)的可修改性,導(dǎo)致后續(xù)重構(gòu)可能會牽一發(fā)而動(dòng)全身。
- 柯里化有一個(gè)很大的特點(diǎn)是函數(shù)嵌套,這不符合"never nester"不嵌套主義的編程理念。嵌套會大幅降低可讀性。
如果你真的打算使用柯里化的編程風(fēng)格。小編建議你,寫全注釋!
一直寫到,我不需要讀你的函數(shù),就知道你這個(gè)函數(shù)想做什么、有幾個(gè)參數(shù)、想返回什么、什么情況下會結(jié)束柯里化。
面向?qū)ο缶幊田L(fēng)格函數(shù)
代碼
// 面向?qū)ο箫L(fēng)格函數(shù)
export function count() {
// 總和屬性
this._sum = 0;
// 添加方法方法
this.add = (i) => this._sum += i;
// 返回總和方法
this.get = () => this._sum;
// 返回構(gòu)造對象
return this;
}
/*
// 使用樣例
* a = count();
* console.log(a.add(10));
* console.log(a.add(20));
* a.add(30);
* console.log(a.get());
*/
解讀
相對于下文提到的鏈?zhǔn)骄幊?、更加正統(tǒng)的面向?qū)ο箫L(fēng)格。每一次運(yùn)算結(jié)果清晰、類型明確,在現(xiàn)代化的編程工具幫助下,編程效率很高。
面向?qū)ο箫L(fēng)格函數(shù)、鏈?zhǔn)骄幊?/h3>代碼
//面向?qū)ο箧準(zhǔn)骄幊田L(fēng)格
// 構(gòu)造函數(shù)
export function count2() {
// 總和屬性
this._sum = 0;
// 添加方法
this.add = (is) => ((this._sum += is), this);
// 求和方法
this.get = () => this._sum
// 返回構(gòu)造對象
return this;
}
/*使用樣例
console.log(count().add(10).add(20).add(30).get());
*/
解讀
//面向?qū)ο箧準(zhǔn)骄幊田L(fēng)格
// 構(gòu)造函數(shù)
export function count2() {
// 總和屬性
this._sum = 0;
// 添加方法
this.add = (is) => ((this._sum += is), this);
// 求和方法
this.get = () => this._sum
// 返回構(gòu)造對象
return this;
}
/*使用樣例
console.log(count().add(10).add(20).add(30).get());
*/
我之所以將它從面向?qū)ο髥为?dú)拎出來,是因?yàn)槊嫦驅(qū)ο箧準(zhǔn)斤L(fēng)格編程、基本可以代替柯里化編程。
這種編程風(fēng)格相對于柯里化更加扁平,可讀性更高,還具備一定的可拓展性。
所以,如果在可以選的情況下為什么要使用柯里化呢?
聲明式風(fēng)格函數(shù)
代碼
// 聲明式風(fēng)格函數(shù)
export function sum3(is, get) {
let ans = 0;
// 這里可以使用任何實(shí)現(xiàn)方式,可以使用異步等方式實(shí)現(xiàn)
is.forEach(element => {
ans += element;
});
// 無論用任何方式實(shí)現(xiàn),最后所有運(yùn)算結(jié)束后都使用get函數(shù)作為回調(diào)。
get(ans)
}
解讀
聲明式風(fēng)格的函數(shù)特點(diǎn)不在于它代碼是怎樣的,而是在于它提供了哪些參數(shù)供開發(fā)者調(diào)用。開發(fā)者不在去關(guān)心實(shí)現(xiàn)的順序,如何實(shí)現(xiàn)、因?yàn)槿绾螌?shí)現(xiàn)根本不重要,實(shí)現(xiàn)順序也不重要。你想要的只有答案,和得到答案。實(shí)現(xiàn)可以使用任何方式實(shí)現(xiàn),內(nèi)部可以使用多線程、異步、或者等等的方法實(shí)現(xiàn)。
總結(jié)
現(xiàn)代編碼風(fēng)格的演變,無非就是隨著需要處理問題的改變,產(chǎn)生了關(guān)注的點(diǎn)的改變。去改變開發(fā)者的注意力,讓開發(fā)者放置跟多的精力在自己的業(yè)務(wù)上。不是越先進(jìn)的編碼風(fēng)格就越好用,在合適的地方選擇合適的編碼風(fēng)格才是最重要的。