# 提升代码健壮性
# 更安全地访问数据
当我们请求完一个接口,返回一个response时,我们会下意识地用解构赋值,将data取出来然后做逻辑操作。但后台有时给的data并不是数组类型。因此用上Array.isArray检查数据类型。
const {data} = res;
Array.isArray(data) && data.forEach(()=>{});
# 空值合并运算符
假设有个对象里还嵌套着2层对象,为了取最里面的值,开发可能会这么写。
let obj = { a:{b:{c:1}}};
// 用&&挨个判断是否存在
let value = obj && obj.a && obj.a.b&& obj.a.b.c;
而在ES2020中,提出了控制合并运算符的草案,包括??和?.运算符,实现了安全访问对象属性的功能。
let obj = { a:{b:{c:1}}};
// 用了空值合并运算符后
let value = obj?.a?.b?.c;
# 封装一个安全获取对象属性API
function getObjectValueByKeyStr(obj, key, defaultVal = undefined) {
if (!key) return defaultVal;
let namespace = key.toString().split(".");
let value,
i = 0,
len = namespace.length;
for (; i < len; i++) {
value = obj[namespace[i]];
// 若未定义或为空,则返回undefinded
if (value === undefined || value === null) return defaultVal;
obj = value; // 下轮循环,obj将为深层
}
return value;
}
var x = { y: { z: 100,},};
var val = getObjectValueByKeyStr(x, "y.z");
// var val = getObjectValueByKeyStr(x, "zz");
console.log(val);
用reduce简写
function getSecurityValueByObject(obj,key){
let keyArr = String.prototype.split.call(key,".");
return keyArr.reduce((pre,cur)=>{
if(pre == null || pre == undeinfed) return undeinfed;
return pre = pre[cur];
},obj);
}
var x = { y: { z: 100,},};
var val = getSecurityValueByObject(x, "y.z");
console.log(val); // 100
# 更稳定的第三方模块
平时在项目开发中,可能会遇到一些小需求,比如日期格式化、数据深拷贝等。因为不习惯于在npm寻找模块,导入项目中来用,这之间包括了寻找模块、下载模块、导入模块、查看使用教程,需要短时间的学习成本。所以选择了自己手写一个功能供自己或项目组里的同事一起使用。
# 设备适配例子
export function getOSType() {
const ua = navigator.userAgent
const isWindowsPhone = /(?:Windows Phone)/.test(ua)
const isSymbian = /(?:SymbianOS)/.test(ua) || isWindowsPhone
const isAndroid = /(?:Android)/.test(ua)
// 判断是否是平板
const isTablet =
/(?:iPad|PlayBook)/.test(ua) ||
(isAndroid && !/(?:Mobile)/.test(ua)) ||
(/(?:Firefox)/.test(ua) && /(?:Tablet)/.test(ua))
// 是否是iphone
const isIPhone = /(?:iPhone)/.test(ua) && !isTablet
// 是否是pc
const isPc = !isIPhone && !isAndroid && !isSymbian && !isTablet
return {
isIPhone,
isAndroid,
isSymbian,
isTablet,
isPc
}
}
上述例子在某些设备上报错了,在添加修复之后,想到如果又除了其他新的设备,那将还是会报错。于是决定习惯去寻找npm里的模块,下载并使用它们。比如mobile-detect这个库。
# 模块导入的副作用
为实现功能而导入模块,将会带来下列问题:
- 会增加文件打包时的体积。
- 可能会给项目带来安全问题,使用前需要对源码code review。
# 在本地配置文件
在开发环境中,有时候需要配置本地的调试入口。那么可以在本地新创建一个配置文件,并在.gitignore中忽略他
// config.local.js
module.export = {
needMock,
}
// .gitignore
config.local.js
如若在其他的电脑设备上拉代码,则需要try...catch来让其他设备环境中进入catch流程。
// mock/entry.js
// 因为只有本地有config.local.js,因此直接进入catch
try {
const { needMock } = require('./config.local')
if (needMock) {
require('./index') // 对应的mock入口
console.log('====start mock api===')
}
} catch (e) {
console.log('未引入mock,如需要,请创建/mock/config.local并导出 {needMock: true}')
}
最后配置启动的环境
if (process.env.NODE_ENV === 'development') {
require('../mock/entry')
}
# Code Review
CR在开发中是非常重要的一个点,它将消除开发与需求对文档中的功能的理解。该过程中,开发可以提出自己对技术的看法、在开发过程中遇到的困难,或者对需求有更好的逻辑想法,同时可以确认每一位开发人员的进度。总结上述几点:
- 确认消除对需求理解的偏差。
- 优化代码质量,包括冗余代码、变量命名和过分封装等等,保证每个函数没有副作用、保证模块低耦合。该注释的地方需要强调等。
# 总结
提高JavaScript代码的健壮性的方法,主要有以下几点:
- 对接收数据进行安全检验。数组使用Array.isArray。对象则手写个迭代api,检测是否是null或undefined值。
- 本地环境配置,注意在.gitignore忽略到该配置文件,并写上try...catch语句控制引入,防止其他人拉代码时报错。
- 开发过程中,难免需要一些小功能,这时候可以选择手写,也可以选择导入模块,在确保不会给项目带来安全隐患的情况下,导入模块会更好一些,避免手写API带来的错误。
- 每隔一段时间施行一次Code Review,能有效减少开发与需求理解上的偏差。并且保证代码能长期保持高质量水平,易于维护。