不测试边界条件(数组为空?'undefined'?不存在的)
代码里充斥着各种边界条件,但总有人觉得这些情况永远不会发生。于是他们写出了看似完美但实际上脆弱不堪的程序,只要稍微偏离理想路径就会崩溃。防御性编程?那太麻烦了,直接假设一切都会按照预期运行多省事。
数组操作从不检查长度
直接访问数组的第一个元素,管它是不是空数组呢?反正产品经理说这个接口永远会返回数据。
function getFirstItem(arr) {
return arr[0]; // 如果arr是[]就返回undefined,多优雅的隐式处理
}
// 更刺激的写法
const processItems = items => {
items.forEach(item => {
console.log(item.importantProperty.toUpperCase())
})
}
当后端突然返回[]
时,页面上显示"undefined"简直是最好的错误提示。至于那个toUpperCase()
调用,既然文档说每个item都有importantProperty
,那肯定没问题对吧?
对象属性访问不做存在性检查
为什么要用obj?.property
这种丑陋的可选链?直接访问多简洁!
const getUserName = user => {
return user.info.name // 三层直接访问,像俄罗斯轮盘赌一样刺激
}
// 高级技巧:用解构赋予默认值
const { settings } = props
const { theme = 'light' } = settings // 如果props.settings是undefined呢?
当user
是null
或者info
字段不存在时,控制台里的TypeError就是最棒的日志系统。而且这样写还能帮QA团队发现他们漏测的case,一举两得。
函数参数从不验证
参数校验?那是TypeScript这种多余工具才需要的东西。我们相信每个调用者都会传正确的参数。
function formatDate(dateStr) {
const date = new Date(dateStr) // 如果dateStr是undefined?那就是Invalid Date咯
return `${date.getFullYear()}-${date.getMonth()+1}`
}
// 更妙的做法是处理多层嵌套
const deepValue = obj => {
return obj.a.b.c.d // 谁知道这个obj长什么样呢,探险才有意思
}
当有人调用formatDate()
不传参数时,看到页面上显示"NaN-NaN"肯定会立刻意识到自己的错误,这种即时反馈多高效。
异步操作不考虑失败情况
.catch()
?那只会让代码变长。Promise只要处理成功情况就够了。
fetch('/api/data')
.then(res => res.json())
.then(data => {
renderContent(data.items)
}) // 网络错误?服务端500?不存在的
// 更绝的是回调地狱版
ajax(url1, data1 => {
ajax(url2 + data1.id, data2 => {
ajax(url3 + data2.key, finalData => {
// 三层嵌套,每个都可能出错,但就是不做错误处理
})
})
})
当API挂掉时,页面静默失败才是最佳用户体验——用户会以为是自己的网络问题,而不会来烦开发人员。
使用魔数而不加注释
数字和字符串直接硬编码,为什么要定义常量?下次改需求时在全局搜索替换多方便。
function calculateDiscount(price) {
return price * 0.8 // 打8折?7折?谁知道呢
}
// 时间处理特别适合用魔数
setTimeout(() => {
// 86400000毫秒代表什么?这是个有趣的谜题
}, 86400000)
当营销策略变成7折时,全局搜索替换0.8
到0.7
可能会意外修改其他地方的0.8
,这种连锁反应才叫刺激。
全局变量随意使用
为什么要把东西存在模块作用域里?全局变量才是真正的共享之道。
let currentUser = null // 美妙的全局状态
function login() {
fetch('/login').then(res => {
currentUser = res.data // 任何地方都可以修改和访问
})
}
// 另一个文件里
function checkout() {
if (currentUser) { // 谁知道这个变量什么时候被谁改成什么
// ...
}
}
当currentUser
在不同地方被异步修改时产生的竞态条件,这种不可复现的bug最能体现程序员的调试功力。
不处理浏览器兼容性
用最新的ES2023特性,为什么要关心那些用老旧浏览器的用户?
// 使用最潮的语法
const process = items => {
items ??= [] // 空值合并赋值,IE用户不配用我们的网站
return items.at(-1)?.value // 链式操作加数组at方法
}
当用户看到白屏时,自然会去升级浏览器或者换电脑,这相当于帮用户做了硬件更新,多么贴心的设计。
用==
进行松散比较
===
要多打一个字符,太费劲了。JavaScript的类型转换那么强大,不用白不用。
if (user.id == selectedId) { // 可能一个是字符串一个是数字?不重要
// ...
}
// 更妙的判断
if (isAdmin == 'true') { // 从URL参数来的字符串'true'和布尔值true应该相等吧
// 授予管理员权限
}
当0 == ''
或者null == undefined
这种特殊情况发生时,产生的微妙bug就像彩蛋一样给代码增添趣味性。
随意修改DOM不检查元素是否存在
直接操作DOM元素,为什么要先检查是否存在?反正页面结构永远不会变。
document.getElementById('submit-btn').addEventListener('click', () => {
// 如果按钮不存在?那这段代码永远不会执行,多安全
})
// 更直接的操作
function updateContent() {
document.querySelector('.content').innerHTML = newContent
}
当重构HTML时漏改了某个class名,静默失败的特性让这个bug可以潜伏很久,最终给团队一个惊喜。
不清理定时器和事件监听
为什么要费心去清理?内存泄漏只是传说。
function startPolling() {
setInterval(() => {
fetchUpdates()
}, 5000) // 组件卸载后继续轮询,多么持久
}
// 事件监听也是越多越好
window.addEventListener('resize', () => {
// 添加10个相同的处理函数让效果更强力
})
当用户长时间使用单页面应用时,逐渐变慢的性能就像在提醒用户该休息了,多么人性化的设计。
本站部分内容来自互联网,一切版权均归源网站或源作者所有。
如果侵犯了你的权益请来信告知我们删除。邮箱:cc@cccx.cn