在 JS 中,除了变量,用的最多的应该就是函数了,函数是 Javascript 的第一公民。
要写好一个函数,个人认为,可以从以下几点来编写:
命名准确
函数注释
函数参数
函数的返回
本文对以上几点做了梳理和总结,希望能对大家有所帮助。
函数名称
这应该是最基本的要求了,函数的命名需要明确,语义清晰,简单概括函数的功能。我们不要想着代码简短而缩短函数名称,这并不会提高什么性能或效率,相反,一个函数名称若不够清晰,往往其他人无法理解。
除了一些都所有人知道的名次(我们这边的 SKU
)缩写外,一些相对来讲比较少人知道的专业名次就尽量不要使用缩写。
尽量使用动词,比如:getXxxxx
、setXxxxx
,动词在前面,语义就能更加清晰。
2 . 参数命名
参数的命名同样重要,我们都强调语义化,参数命名让调用者更清晰的知道该传入什么,对应什么参数。当然,像一些通用命名还是可接受的,像 callback
,fn
,即使不看注释,往往我也知道这里的参数要做什么,传什么。
当我们的命名准确后,我们也不可能让每一个看代码的人都通过名称就知道这个函数在做什么,这个参数代表什么。因此,函数一定要写注释,具体的交互代码不写,但函数的功能,参数至少是不可避免的。
/**
* 时间格式化工具函数
*
* @param { (Date | number) } date - 时间
* @param { string } unit - 转换格式
*/
export const timeFormat = (date: Date | number | string, unit: string) => {
if (!date) {
return ''
}
if (typeof date === 'string') return date;
if (typeof date === 'number') {
date = new Date(date);
}
const year = date.getFullYear();
const month = date.getMonth() + 1;
const day = date.getDate();
const hour = date.getHours();
const minute = date.getMinutes();
const second = date.getSeconds();
if (unit === 'year') return `${year}`;
if (unit === 'month') return `${year}-${month}`;
if (unit === 'day') return `${year}-${month}-${day}`;
if (unit === 'hour') return `${year}-${month}-${day} ${hour}`;
if (unit === 'minute') return `${year}-${month}-${day} ${hour}:${minute}`;
if (unit === 'second') return `${year}-${month}-${day} ${hour}:${minute}:${second}`;
}
像上面这个例子,参数前面都加了一个 @param
,表明这个是参数的注释。
一般的格式为 @param { type } 参数 - 参数解释
。
type
表明的是参数的类型,比如 string
,number
,当有多个参数类型的时候,可以这么来标识 { (string|string[]) }
,表示这个参数可以是字符串或者字符串数组。
还有其他的参数注释可以这么来写
/**
* Assign the project to an employee.
* @param {Object} employee - The employee who is responsible for the project.
* @param {string} employee.name - The name of the employee.
* @param {string} employee.department - The employee's department.
*/
Project.prototype.assign = function(employee) {
// ...
};
有两种语法 JSDoc
和 Google Closure Compiler
JSDoc
语法
/**
* 时间格式化工具函数
*
* @param { (Date | number) } date - 时间
* @param { string } [unit] - 转换格式
*/
export const timeFormat = (date: Date | number | string, unit: string) => {
// ...
}
Google Closure Compiler
语法
/**
* 时间格式化工具函数
*
* @param { (Date | number) } date - 时间
* @param { string= } unit - 转换格式
*/
export const timeFormat = (date: Date | number | string, unit: string) => {
// ...
}
/**
* 时间格式化工具函数
*
* @param { (Date | number) } date - 时间
* @param { string } [unit = 'second'] - 转换格式
*/
export const timeFormat = (date: Date | number | string, unit: string) => {
// ...
}
2 . 函数注释
函数的功能点需要表明,一个函数一个功能,这就是我们说的 单一功能
,一个函数就做一件事,因此注释也只会说明函数做了哪一件事。
3 . 其他注释
除了 @param
之外,还有其他的类型
参数默认值
有时候,当一个函数的参数不那么必要,或者某一个值相对应用较多,就应该考虑加上一个默认值,比如上面的时间转换工具,参数就应该这么写。
export const timeFormat = (date: Date, unit = 'second') => {
// ...
}
当我们的业务中需要 YYYY-MM-DD hh:mm:ss
这样的格式较多的时候,unit
默认就是 second
, 这样,当我们调用函数的时候,可以只传一个 date
参数,而不需要在每一处调用的代码都写上 timeFormat(new Date(), 'second')
。
2 . 对象参数
在一段打印代码中,参数多达十几个。像下面这个 打印函数
。
async function printer_proxy_print(
html_str: string,
file_path: string,
device: string | undefined,
orientation: number,
printer_mode: string,
width: number,
height: number,
scale: number,
from: number,
to: number,
left_offset: number,
top_offset: number,
pdf_tools: string | undefined,
begin_page = 1,
end_page = 1,
repeat_times = 1,
print_type: string
) {
// ...
}
这个时候,我们可以给参数默认值,这样可以只传前面几个必要的参数,像这样调用。
async function printer_proxy_print(
html_str: string,
file_path: string,
device = 'pc',
orientation = 'xxx',
printer_mode = 'xxx',
width = 123,
height = 123,
scale = 123,
from = 123,
to = 123,
left_offset = 123,
top_offset = 123,
pdf_tools = 123,
begin_page = 1,
end_page = 1,
repeat_times = 1,
print_type = 'base64'
) {
// ...
}
await printer_proxy_print(html_str, file_path);
上面的方法看似可行,实际上,当我中间某个参数不一样的时候,我就需要把这个参数前面的参数都传一遍。这样显然不可行。所以当参数多的时候,我们需要用对象解构的方式传参。
async function printer_proxy_print({
html_str,
file_path,
device = 'pc',
orientation = 'xxx',
printer_mode = 'xxx',
width = 123,
height = 123,
scale = 123,
from = 123,
to = 123,
left_offset = 123,
top_offset = 123,
pdf_tools = 123,
begin_page = 1,
end_page = 1,
repeat_times = 1,
print_type = 'base64'
}) {
// ...
}
await printer_proxy_print({html_str, file_path});
解构的好处便是我可以随便传我想要的某几个参数,而不用在意顺序问题。不过像这么多参数的函数往往存在问题(具体问题具体分析)。也就是下面提到的参数数量问题。
3 . 参数数量
一个函数的参数越少越好,最多不应该超过3个,参数多往往意味着关系多,逻辑交叉相对也就多了起来。在进行测试的时候,往往也就很难覆盖到所有条件,出问题概率也就加大了。
参数多的时候,有时候也意味着功能多,就违背了 单一功能
的原则。
4 . 参数类型防御
在 TS 开发前,我们不知道用户会传什么东西进来,这时候往往容易产生类型错误,又或者,我们想实现兼容,像前面的 timeFormat
函数,我们希望用户调用的时候,可以是想对 时间对象
格式化,也可以是对 时间戳
格式化,那我们就需要做一个防御处理。
if (!date) {
return ''
}
if (typeof date === 'string') return date;
if (typeof date === 'number') {
date = new Date(date);
}
不过值得注意的是,即使我们用上了 TS,在大多数情况下,我们确实可以避免参数类型问题,但是这并不绝对,因为我们有时候会直接接受 接口
返回的数据。
我们常说,永远不要相信用户的输入,同样,接口返回的数据我也不信,我们不能保证,后端不会出错,约定好的参数是数组类型,怎么空的时候,你给我个 null
呢?
当然这些情况有时候需要去试错,有时候我们能想到的可能,不要偷懒,给写上类型判断吧。
幂等
什么叫幂等,简单来说,输入什么输出什么是固定的,入参决定了出参,不管调用多少次,只要输入一样,结果应该保持一样。
简单的例子:
function sum(a: number, b: number) {
return a + b;
}
幂等函数具有可维护性,相对容易进行单元测试。
2 . 纯函数
纯函数在幂等的条件下,还要求没有副作用。
举个例子:
const dog = {
name: 'puppy',
age: 2,
weight: 30,
}
if (!dog.color) {
console.log('has no color');
}
function addColor(dog) {
dog.color = 'white';
}
addColor(dog);
console.log(dog); // {name: "puppy", age: 2, weight: 30, color: "white"}
可以看到,addColor
函数修改了 dog
对象的属性,也就是产生了副作用,我们应该怎么做修改会合理点呢?可以像下面这样:
function addColor(dog) {
let copyDog = Object.assign({}, dog);
copyDog.color = 'white';
return copyDog;
}
这样一来,dog
对象的属性就不会修改,addColor
函数是纯函数。
3 . return null
null
在进行处理的时候相对麻烦,需要进行判断,导致了额外的代码,应当返回空对象,或者是空数组,或者抛出异常。
良好的代码,自带注释。
希望大家都能养成好的习惯。
谢谢。
本文由哈喽比特于3年以前收录,如有侵权请联系我们。
文章来源:https://mp.weixin.qq.com/s/9Ld0cg-9ror93MxSE5Cwfw
京东创始人刘强东和其妻子章泽天最近成为了互联网舆论关注的焦点。有关他们“移民美国”和在美国购买豪宅的传言在互联网上广泛传播。然而,京东官方通过微博发言人发布的消息澄清了这些传言,称这些言论纯属虚假信息和蓄意捏造。
日前,据博主“@超能数码君老周”爆料,国内三大运营商中国移动、中国电信和中国联通预计将集体采购百万台规模的华为Mate60系列手机。
据报道,荷兰半导体设备公司ASML正看到美国对华遏制政策的负面影响。阿斯麦(ASML)CEO彼得·温宁克在一档电视节目中分享了他对中国大陆问题以及该公司面临的出口管制和保护主义的看法。彼得曾在多个场合表达了他对出口管制以及中荷经济关系的担忧。
今年早些时候,抖音悄然上线了一款名为“青桃”的 App,Slogan 为“看见你的热爱”,根据应用介绍可知,“青桃”是一个属于年轻人的兴趣知识视频平台,由抖音官方出品的中长视频关联版本,整体风格有些类似B站。
日前,威马汽车首席数据官梅松林转发了一份“世界各国地区拥车率排行榜”,同时,他发文表示:中国汽车普及率低于非洲国家尼日利亚,每百户家庭仅17户有车。意大利世界排名第一,每十户中九户有车。
近日,一项新的研究发现,维生素 C 和 E 等抗氧化剂会激活一种机制,刺激癌症肿瘤中新血管的生长,帮助它们生长和扩散。
据媒体援引消息人士报道,苹果公司正在测试使用3D打印技术来生产其智能手表的钢质底盘。消息传出后,3D系统一度大涨超10%,不过截至周三收盘,该股涨幅回落至2%以内。
9月2日,坐拥千万粉丝的网红主播“秀才”账号被封禁,在社交媒体平台上引发热议。平台相关负责人表示,“秀才”账号违反平台相关规定,已封禁。据知情人士透露,秀才近期被举报存在违法行为,这可能是他被封禁的部分原因。据悉,“秀才”年龄39岁,是安徽省亳州市蒙城县人,抖音网红,粉丝数量超1200万。他曾被称为“中老年...
9月3日消息,亚马逊的一些股东,包括持有该公司股票的一家养老基金,日前对亚马逊、其创始人贝索斯和其董事会提起诉讼,指控他们在为 Project Kuiper 卫星星座项目购买发射服务时“违反了信义义务”。
据消息,为推广自家应用,苹果现推出了一个名为“Apps by Apple”的网站,展示了苹果为旗下产品(如 iPhone、iPad、Apple Watch、Mac 和 Apple TV)开发的各种应用程序。
特斯拉本周在美国大幅下调Model S和X售价,引发了该公司一些最坚定支持者的不满。知名特斯拉多头、未来基金(Future Fund)管理合伙人加里·布莱克发帖称,降价是一种“短期麻醉剂”,会让潜在客户等待进一步降价。
据外媒9月2日报道,荷兰半导体设备制造商阿斯麦称,尽管荷兰政府颁布的半导体设备出口管制新规9月正式生效,但该公司已获得在2023年底以前向中国运送受限制芯片制造机器的许可。
近日,根据美国证券交易委员会的文件显示,苹果卫星服务提供商 Globalstar 近期向马斯克旗下的 SpaceX 支付 6400 万美元(约 4.65 亿元人民币)。用于在 2023-2025 年期间,发射卫星,进一步扩展苹果 iPhone 系列的 SOS 卫星服务。
据报道,马斯克旗下社交平台𝕏(推特)日前调整了隐私政策,允许 𝕏 使用用户发布的信息来训练其人工智能(AI)模型。新的隐私政策将于 9 月 29 日生效。新政策规定,𝕏可能会使用所收集到的平台信息和公开可用的信息,来帮助训练 𝕏 的机器学习或人工智能模型。
9月2日,荣耀CEO赵明在采访中谈及华为手机回归时表示,替老同事们高兴,觉得手机行业,由于华为的回归,让竞争充满了更多的可能性和更多的魅力,对行业来说也是件好事。
《自然》30日发表的一篇论文报道了一个名为Swift的人工智能(AI)系统,该系统驾驶无人机的能力可在真实世界中一对一冠军赛里战胜人类对手。
近日,非营利组织纽约真菌学会(NYMS)发出警告,表示亚马逊为代表的电商平台上,充斥着各种AI生成的蘑菇觅食科普书籍,其中存在诸多错误。
社交媒体平台𝕏(原推特)新隐私政策提到:“在您同意的情况下,我们可能出于安全、安保和身份识别目的收集和使用您的生物识别信息。”
2023年德国柏林消费电子展上,各大企业都带来了最新的理念和产品,而高端化、本土化的中国产品正在不断吸引欧洲等国际市场的目光。
罗永浩日前在直播中吐槽苹果即将推出的 iPhone 新品,具体内容为:“以我对我‘子公司’的了解,我认为 iPhone 15 跟 iPhone 14 不会有什么区别的,除了序(列)号变了,这个‘不要脸’的东西,这个‘臭厨子’。