声明
JavaScript编程过程中函数是一个很有趣的点,JavaScript的函数与其他如:C、Java等语言有很大区别。对于从别的编程语言转来的同学可能会存在一定的“坑”,如function函数与=>函数的区别。function函数this关键字的占用等。
在下文的案例中可能会使用这些知识,但我因为篇幅限制将不会对这些语法进行讨论,只讨论不同编码方式的风格问题。
测试环境申明
测试工具:DevEco Studio 3.1.1 Release 构建版本:3.1.0.501
测试平台:HarmonyOS Api9 x86 虚拟机
测试语言:ArkTS(只测试JavaScript语法部分)
简介
因为JavaScript编程风格的灵活性。在一个简单的求和函数、在JavaScript中可以使用很多不同的风格表示。
小编将会以函数式编程、面向对象编程、面向对象链式编程、申明式编程等多个不同的方式表示出来。
以下代码仅作为抛砖引玉的效果,不代表实际开发代码,也不代表当下所有的编码风格,小编只谈论我了解的几种。在实际开发过程中每一种编码风格也会存在更多的细分风格。
过程式编程
代码
// 过程式编程
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));
*/
解读
过程式编程是最简单粗暴直接的编程方式,在所有主流编程语言中都支持使用过程式编程。
过程式编程往往需要编程者拥有过硬的编程素养与对业务的深刻理解才可以保证代码的持续性的可维护性、可扩展性。
在业务不确定、实现逻辑经常变化、实现方案不稳定的部分不建议使用这种编码风格,因为它很容易导致代码失控。
但是在算法实现上,笔者强烈建议各位使用这种编码风格。它简单可靠,可以节约编程者的许多心智。
柯里化编程
代码
// 自动柯里化机,可以自动把函数转化为柯里化风格。
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));
}
}
}
}
// 获得转化后的函数
export const curriedAdd = curry(add2);
/**
* 使用样例
* console.log(curriedAdd(1)(2)); // 3
* console.log(curriedAdd(1, 2)); // 3
* console.log(curriedAdd(1)(2, 3)); // 3
*/
解读
柯里化编程有一个有特色的地方是函数的连续嵌套,这是前端开发非常热门的一种编程方式。但小编极力反对这种编程方式具体原因有一下几点:
- 柯里化编程虽然确实提高了开发的灵活性,但是它也降低了函数的可修改性,导致后续重构可能会牵一发而动全身。
- 柯里化有一个很大的特点是函数嵌套,这不符合"never nester"不嵌套主义的编程理念。嵌套会大幅降低可读性。
如果你真的打算使用柯里化的编程风格。小编建议你,写全注释!
一直写到,我不需要读你的函数,就知道你这个函数想做什么、有几个参数、想返回什么、什么情况下会结束柯里化。
面向对象编程风格函数
代码
// 面向对象风格函数
export function count() {
// 总和属性
this._sum = 0;
// 添加方法方法
this.add = (i) => this._sum += i;
// 返回总和方法
this.get = () => this._sum;
// 返回构造对象
return this;
}
/*
// 使用样例
* a = count();
* console.log(a.add(10));
* console.log(a.add(20));
* a.add(30);
* console.log(a.get());
*/
解读
相对于下文提到的链式编程、更加正统的面向对象风格。每一次运算结果清晰、类型明确,在现代化的编程工具帮助下,编程效率很高。
面向对象风格函数、链式编程
代码
//面向对象链式编程风格
// 构造函数
export function count2() {
// 总和属性
this._sum = 0;
// 添加方法
this.add = (is) => ((this._sum += is), this);
// 求和方法
this.get = () => this._sum
// 返回构造对象
return this;
}
/*使用样例
console.log(count().add(10).add(20).add(30).get());
*/
解读
我之所以将它从面向对象单独拎出来,是因为面向对象链式风格编程、基本可以代替柯里化编程。
这种编程风格相对于柯里化更加扁平,可读性更高,还具备一定的可拓展性。
所以,如果在可以选的情况下为什么要使用柯里化呢?
声明式风格函数
代码
// 声明式风格函数
export function sum3(is, get) {
let ans = 0;
// 这里可以使用任何实现方式,可以使用异步等方式实现
is.forEach(element => {
ans += element;
});
// 无论用任何方式实现,最后所有运算结束后都使用get函数作为回调。
get(ans)
}
解读
声明式风格的函数特点不在于它代码是怎样的,而是在于它提供了哪些参数供开发者调用。开发者不在去关心实现的顺序,如何实现、因为如何实现根本不重要,实现顺序也不重要。你想要的只有答案,和得到答案。实现可以使用任何方式实现,内部可以使用多线程、异步、或者等等的方法实现。
总结
现代编码风格的演变,无非就是随着需要处理问题的改变,产生了关注的点的改变。去改变开发者的注意力,让开发者放置跟多的精力在自己的业务上。不是越先进的编码风格就越好用,在合适的地方选择合适的编码风格才是最重要的。