迷惑代码赏析第1期

开发工作中遇到了许多的 💩⛰ 代码,这个系列里就大家分享&吐槽一下。

同时也分享一下最近深度使用的专业编程显示器👨🏻‍💻👍🏻 🖥

攒够素材就更新下一期,有好的素材也欢迎投稿,推荐!

1 random了寂寞

目的是将目标值和一个[0,100)的随机数比较,但结果一直是 FAILED

让我们来看一下现在实现的代码 ↓:

js 复制代码
function can(compareTo) {
  return Number.parseInt(Math.random * 100) > compareTo
    ? Status.SUCCESS
    : Status.FAILED
}

💩 问题:Math.random,没有被调用,所以判断执行值始终是 NaN

最终生效判断代码如下:

js 复制代码
function can(compareTo) {
  return NaN > compareTo
    ? Status.SUCCESS
    : Status.FAILED
}

NaN 与其它值进行 ><= 运算都是 false 所以这里逻辑不符合预期。

遇到这种💩,你觉得修还是不修!

一点补充:这段代码跑了好多年了,说明这个错误的执行结果符合现状。

2 执行一次的定时器

使用定时器的场景很常见,比如延后执行一次逻辑:

但看到下面这种代码你说难受不难受?

js 复制代码
const timer = setTimeout(() => {
  clearTimeout(timer)
  console.log('exec once')
}, 1000)

💩问题: setTimeout,本身就只执行一次,所以这里的 clearTimeout 多余。

js 复制代码
const timer = setInterval(() => {
  clearInterval(timer)
  console.log('exec interval once')
}, 1000)

💩问题: setInterval,用于循环执行,这种执行一次的场景,建议使用 setTimeout

代码功能没问题,但对于有代码洁癖的来说,看着比较难受。

很多仓库都有这个💩,不知道是谁带的头!

3 非必要的 async

经常看到一些方法,内部就只是同步逻辑,但不知道是什么坏习惯性加了 async

这会导致返回内容始终为一个 Promise

js 复制代码
async function test() {
  return 'hello'
}

调用的时候同步取值就需要 await ,同时方法本身也需要被迫添加 async

💩 问题:容易破坏存量代码结构,甚至影响执行顺序。

下面就是同步和异步的执行结果区别

这种坑还是少一点好。

4 非必要的判断

返回值是 boolean 的时候,通常可以简化掉相关的判断。

来看看 bad case:

js 复制代码
function case1() {
  if (xx) {
    return true
  }
  return false
}

function case2() {
  return xx ? true : false
}

💩 问题:判断条件执行结果本来就是 boolean,不需要再多此一举。

js 复制代码
function case() {
  return 判断条件
}

我相信大部分同学都遇到过这种冗余的判断,如果是为了凑代码量,那我建议多写注释。

5 冗余的else-if

一个取配置的场景:从不同的配置对象中取出同一意义的值

js 复制代码
function getConfigValue(type, cfg) {
  if (type === 'xxx') {
    return cfg.id
  }
  else if (type === 'yyy') {
    return cfg.key
  }
  else if (type === 'zzz') {
    return cfg.secret
  }
  // 此处省略数十个判断。。。
}

💩 问题:重复浓度过高,一屏都是这种 else-if

个人倾向这种场景做成配置化,便于拓展,不用频繁改代码。

js 复制代码
const config = {
  xxx: 'id',
  yyy: 'key',
  zzz: 'secret',
}

function getConfigValue(type, cfg) {
  return cfg[config[type]]
}

猜测写第一版的人可能只写了几个 else-if 然后后面修改的人就不断的 CV,才导致现在这样冗长。

6 假同步执行

页面上有个功能时好时坏,让我们看看怎么回事 🤔。

看下代码的调用:

js 复制代码
async function mounted() {
  await getProductList()
  await getUserInfo()
  await getUserTags()
  // 此处省略其它处理代码
}

mounted()

大家不妨先按经验推测一下,可能原因,为什么一段代码功能会时好时坏?

下面揭晓一下

js 复制代码
const data = {}

async function getProductList() {
  request('productList').then((res) => {
    data.list = res
  })
}

function getUserInfo() {
  return userSdk.getUserInfo()
}

async function getUserTags() {
  request('userTags', {
    ids: data.list.map(item => item.id)
  }).then((res) => {})
}

💩 问题: 异步方法返回内部没有等待内部逻辑执行完就提前结束了

时好时坏的原因就看网络情况,接口请求快就能拿到依赖的数据,慢就没数据。

正确写法是等待内部所有异步结束,或返回其执行结果,否则默认返回值是 Promise.resolve(undefined)

js 复制代码
async function rightCode() {
  return request('/api')
}

async function rightCode() {
  await request('/api')
}

这个问题一个项目里处理了好几次,不能说每次都粗心吧,写的人真就是没认真学习!

7 非预期的执行顺序

场景:有个接口返回结果常规的调用接口,返回结果为空时,根据 ok 值真假取不同的兜底值

js 复制代码
const { result, ok } = await fetchData()
const data = result || ok ? obj1 : obj2

如果你看不出问题在哪里,咱们看一下下面的运行结果是什么?

js 复制代码
// 期望返回 1
const value1 = 1 || 2 ? 3 : 4

// 实际返回 3

💩 问题:不一样的原因是 逻辑或 || 运算符优先级高于 三元表达式

这种时候就建议不熟悉同学优先用() 处理执行的代码块

js 复制代码
const data = result || (ok ? obj1 : obj2)

8 v-for 不熟练

① 移除列表元素

vue 复制代码
<script setup>
function handleDelete(item) {
  list1.splice(list1.findIndex(item => item.id === id), 1)
}
</script>

<template>
  <ul>
    <li v-for="item in list1" :key="item.id" @click="handleDelete(item)">
      {{ item.name }}
    </li>
  </ul>
</template>

② 列表渲染添加默认 key

vue 复制代码
<script setup>
import { onMounted } from 'vue'

onMounted(async () => {
  const data = await getData()
  for (let i = 0; i < data.length; i++) {
    list2.push({ ...data[i], id: i })
  }
})
</script>

<template>
  <ul>
    <li v-for="item in list2" :key="item.id">
      {{ item.name }}
    </li>
  </ul>
</template>

💩 问题:v-for 遍历数组本身提供了下标 idx

vue 复制代码
<template>
  <ul>
    <li v-for="(item, idx) in list2" :key="idx" @click="handleDelete(idx)">
      {{ item.name }}
    </li>
  </ul>
</template>

功能没问题,但是不优雅,知识学习没到位。

9 冗余重复代码

① 重复的字符串拼接

js 复制代码
const baseURL = {
  dev: location.protocol + '//' +  'domain1',
  test: location.protocol + '//' +  'domain2',
  st: location.protocol + '//' +  'domain3',
  prod: location.protocol + '//' +  'domain4',
  mock: location.protocol + '//' +  'domain5',
}

const host = baseURL[env]

💩 问题:书写有些冗余,有简化空间

js 复制代码
const baseURL = {
  dev: 'domain1',
  test: 'domain2',
  st: 'domain3',
  prod: 'domain4',
  mock: 'domain5',
}

const host = `${location.protocol}//${baseURL[env]}`

最佳做法 还是通过构建工具注入,这样避免代码中存在其它环境的值。

js 复制代码
const host = `${location.protocol}//${process.env.VUE_APP_DOMAIN}`

为什么拉出来吐槽,因为这种代码是在单组件仓库中出现的,C端场景当页面引入几十个组件时候,就多了很多重复代码。

② CSS 冗余写法

css 复制代码
.box {
  margin-top: 10px;
  margin-bottom: 10px;
  margin-left: 10px;
  margin-right: 10px;
}

💩 问题:能简写的属性没有简写

css 复制代码
.box {
  margin: 10px;
}

推荐常用属性能简写的简写。

10 手搓 getQuery

先看看"手搓"的代码。

js 复制代码
function getQuery() {
  const query = {}
  const href = window.location.href
  const searchArray = href.split('?')[1].split('&')
  searchArray.forEach(item => {
    const [key, value] = item.split('=')
    query[key] = value
  })
  return query
}

💩 问题:只考虑了有 Query 的情况,没有 Query 的时候调用就报错了

js 复制代码
href.split('?')[1].split
// Cannot read properties of undefined (reading 'split')

当然也有可优化点,location 提供了 search 属性可直接使用

js 复制代码
function getQuery() {
  const search = location.search
  if(!search){
    return {}
  }
  return search
    .slice(1)
    .split('&')
    .reduce((acc, cur) => {
      const [key, value] = cur.split('=')
      acc[key] = value
      return acc
    }, {})
}

事实上内置的 URLSearchParams 对象,可以直接解析 Query

js 复制代码
function getQuery() {
  const searchParams = new URLSearchParams(location.search)
  return Object.fromEntries(
    searchParams.entries()
  )
}

兼容性允许的情况下,优先推荐使用内置对象或方法实现功能


屏幕看太久,眼睛容易累?下面分享一款 NB 的外设。

编码"物理外挂"

别急着划走🤭,后面还有内容 🙏🏻!

近期深度使用了一款 「程序员专用」 显示器 明基RD280U,分享几个我觉得很棒的地方!

IDE 编码显示优化

你能想象一个显示器居然针对编码的IDE,提供了专门的显示优化!

轻触 logo 即可切换 深色/亮色 模式。

对比一下其它显示器的显示效果!

三星S32A600N 明基RD280U

可以比较明显的看出后者在优化后展示效果更棒,同时屏幕抗环境灯光能力也更强,前者在室内过亮时有些许泛白反光。

使用下来也确实眼睛看着更加的舒服👍🏻!

超Nice的夜间模式

自带背光灯,同时屏幕亮度等显示效果都能随环境光线强弱进行自动调节适应!

关闭室内所有灯光,效果如下

显示效果 背光灯

明基RD280U在无环境光的时候,使用体验也非常不错👍🏻,眼睛不会有不适,屏幕不泛白。

休息提醒

设置

显示器自带的定时休息提示(屏幕右下角弹窗),👨🏻‍💻 日常大部分时间都在坐着,用这个提醒喝水&上厕所&站一站再好不过!

比安装各种提醒软件省事多了!

配套软件特色功能

显示器有一个配套的软件,除了完成硬件配置的功能外,还有一些增强!

配置窗口 桌面分区 自动任务&切换

① 桌面分区

这个比较赞,Mac 系统本身应用分区功能比较弱,需要靠软件补齐这部分能力。

拖动窗口就能自动在鼠标唤起,选择目标分区,窗口就会自动贴合。

② 自动任务

可以设定不同的自动任务流程,不同的模式一键打开设定的一系列应用,同时屏幕调成对应的预设状态

这个功能也是很 nice,一键切换工作/娱乐模式。关机的时候也可不用选择保留关机前的应用了。

接下来咱继续"品鉴代码"

11 冗长的取值判断

场景:深层次嵌套,变量名很长的取值判断。

js 复制代码
function isOk(){
  return (
    testData && 
    testData.helloResult && 
    testData.helloResult.infoDetail && 
    testData.helloResult.infoDetail.type === 'test' &&
    testData.helloResult.infoDetail.status === 'ok'
  )
}

💩 问题:又臭又长的判断,看着比较难受

使用可选链后

js 复制代码
function isOk(){
  return (
    testData?.helloResult?.infoDetail?.type === 'test' &&
    testData?.helloResult?.infoDetail?.status === 'ok'
  )
}

与时俱进的了解新语法还是很有必要

12 莫名其妙的转换

直接看代码

判断有值的时候才做进一步处理

js 复制代码
const value = await fetchData()

if(value && String(value)){
  // 进一步处理
}

💩 问题:再加 String 转换后判断,不是画蛇添足吗?

屏幕前的各位有遇到过没 🤦🏻‍♀️

13 处处 for 循环

① 数量不够时补全数据

js 复制代码
const data = await fetchData()
const count = Math.max(data.length, MIN_COUNT)
for (let i = 0; i < count; i++) {
  if(!data[i]){
    data[i] = {
      id: randomId(),
      otherKey: 'default'
    }
  }
}

💩 问题:不管数量够不够都会存在无意义的遍历!

js 复制代码
const data = await fetchData()
const addedCount = MIN_COUNT - data.length
for(let i = 0; i < addedCount; i++){
  data.push({
    id: randomId(),
    otherKey: 'default'
  })
}

当然也可以使用更优雅的 Array.from 方法生成新数组的过程中完成数据填充

js 复制代码
const data = await fetchData()
if(data.length < MIN_COUNT){
  const addedData = Array.from({length: MIN_COUNT - data.length}, () => ({
    id: randomId(),
    otherKey: 'default'
  }))
  data.push(...addedData)
}

② 根据条件过滤数据

js 复制代码
const data = await fetchData()
const result = []
for (let i = 0; i < data.length; i++) {
  if(data[i].value>xx){
    result.push(data[i])
  }
}

💩 问题:过滤场景优先推荐使用 filter 方法

js 复制代码
const data = await fetchData()
const result = data.filter(item => item.value>xx)

③ 增加数据字段

js 复制代码
const data = await fetchData()
for (let i = 0; i < data.length; i++) {
  data[i].newField = getNewField(data[i])
}

💩 问题:这种场景建议使用 map 方法,也不会影响原数组

js 复制代码
const data = await fetchData()
const newData = data.map(item => ({
 ...item,
  newField: getNewField(item)
}))

有些人真只会 for 基础循环一把羧!

最后

真心喜欢写代码的只占少数,草台班子过多🤦🏻‍♀️!

相关推荐
3824278271 天前
JS表单验证:className与classList区别详解
js
REDcker2 天前
Android WebView 版本升级方案详解
android·音视频·实时音视频·webview·js·编解码
winfredzhang3 天前
[实战] Node.js + DeepSeek 打造智能档案归档系统:从混乱到有序的自动化之旅
css·node.js·js·deepseek api
梦凡尘4 天前
前端web端解析 Word、Pdf 文档文本内容
pdf·js
梦凡尘5 天前
Marked.js 的使用及相关问题解决
前端·js
想看一次满天星8 天前
某里231——AST解混淆流程
爬虫·python·ast·js·解混淆
Han.miracle8 天前
JavaScript 基础核心知识点闯关练习
css·js
冥界摄政王8 天前
CesiumJS学习第四章 替换指定3D建筑模型
3d·vue·html·webgl·js·cesium
曲幽10 天前
手把手搞定FastAPI静态文件:安全、上传与访问
css·python·fastapi·web·js·favicon·staticfiles
冥界摄政王10 天前
Cesium学习第二章 camera 相机
node.js·html·vue3·js·cesium