JS 代码技巧 vol.1 — 10 个让代码少写 30% 的小套路

JS 代码技巧 vol.1 --- 10 个让代码少写 30% 的小套路

小不的代码技巧系列第 1 期 主题:判断 · 类型 · 设计模式 主打一个"踩坑 → 解法 → 坑在哪"三段式,看完就能直接抄作业 😎

哈喽哇!我是小不不简说的不~

作为一个在代码界"翻车"无数次的选手,我算是看明白了:坑这东西吧,要么不踩,踩就踩大的😂

今天这期,主打一个 判断 · 类型 · 设计模式------不整虚的,全是实战里哭出来的教训。看不看随你~反正翻车实录又不收钱

Ps:文末有惊喜(不是广告!)


1. 可选链 ?. ------ 干掉 a && a.b && a.b.c

以前写这种代码,血压容易上来:

js 复制代码
// 我以前的写法(血压警告)
if (user && user.profile && user.profile.address && user.profile.address.city) {
  console.log(user.profile.address.city);
}

现在一行搞定:

js 复制代码
console.log(user?.profile?.address?.city);

坑在哪 :可选链遇到 null/undefined 直接 undefined,但遇到 0''false 不会短路------别把它和 && 混用。


2. ?? vs || ------ 0 和 '' 不该被当 falsy

经典踩坑现场:

js 复制代码
function setVolume(vol) {
  return vol || 50; // 用户传 0 进去,默认 50 给你冒出来
}

正解:

js 复制代码
function setVolume(vol) {
  return vol ?? 50; // 只有 null / undefined 才用默认
}

坑在哪?? 不能和 || && 混用(语法直接报错),要加括号隔开。


3. 逻辑赋值三件套:??= / ||= / &&=

赋值 + 逻辑判断,一行搞定。

js 复制代码
let count = 0;
count ||= 10; // count 是 0,被 || 判 falsy → 变成 10
count ??= 10; // count 是 0(不是 null/undefined)→ 不变,还是 0

let user = { name: "小不" };
user.name &&= "[已认证] " + user.name; // name 是 truthy → 加上前缀

坑在哪 :搞不清 ||?? 的区别,三件套一用就翻车。0、空字符串、false 都是 ||= 的受害者。


4. 终极类型判断:Object.prototype.toString.call()

typeof []'object'typeof null 也是 'object',血压 +1。

js 复制代码
function getType(val) {
  return Object.prototype.toString.call(val).slice(8, -1);
  // 返回: 'Array' / 'Date' / 'RegExp' / 'Map' / 'Set' / 'Promise' ...
}

typeof 该用就用(判断基础类型),复杂对象就上 toString,别在 instanceof 上死磕。

坑在哪instanceof 在 iframe / Web Worker 里因为原型链不同会误判,跨窗口场景老老实实用 Array.isArray()


5. Array.isArray() ------ 比 instanceof Array 靠谱

js 复制代码
Array.isArray([]); // true
Array.isArray({ length: 1 }); // false,类数组也能识别

为啥不用 instanceof Array?iframe 里 A 页面的 Array 跟 B 页面的 Array 不是同一个构造函数,[] instanceof Array 会是 false,经典玄学。


6. 单例模式:ES Module 本身就是

别再写这种了:

js 复制代码
class Config {
  constructor() {
    /* ... */
  }
}
Config.instance = null;
Config.getInstance = () => {
  if (!Config.instance) Config.instance = new Config();
  return Config.instance;
};

直接:

js 复制代码
// config.js
export default {
  apiBase: "https://api.example.com",
  // ...
};

ES Module 天然单例,import 多少次都是同一份。需要懒加载再考虑 class。

坑在哪 :CommonJS (Node 老代码) 里 require() 会缓存,但缓存的是 module.exports 的引用,导出对象时小心共享状态。


7. 策略模式:消灭 if/else 嵌套

js 复制代码
// 烂写法(嵌套地狱)
function calc(type, a, b) {
  if (type === "add") return a + b;
  else if (type === "sub") return a - b;
  else if (type === "mul") return a * b;
  else if (type === "div") return a / b;
  else throw new Error("未知运算");
}

正解------查表:

js 复制代码
const ops = {
  add: (a, b) => a + b,
  sub: (a, b) => a - b,
  mul: (a, b) => a * b,
  div: (a, b) => a / b,
};

function calc(type, a, b) {
  const fn = ops[type];
  if (!fn) throw new Error("未知运算");
  return fn(a, b);
}

加新运算?往对象里加一行,不用动 calc

坑在哪 :表里的 key 最好加类型约束(TS 派),不然 calc('addd', 1, 2) 拼错字符串要等到运行时才爆。


8. 观察者模式:30 行 EventEmitter

发布订阅是面试常客,也是真有用。

js 复制代码
class Emitter {
  constructor() {
    this.listeners = new Map();
  }
  on(event, fn) {
    if (!this.listeners.has(event)) this.listeners.set(event, []);
    this.listeners.get(event).push(fn);
  }
  emit(event, ...args) {
    (this.listeners.get(event) || []).forEach((fn) => fn(...args));
  }
  off(event, fn) {
    const arr = this.listeners.get(event);
    if (arr)
      this.listeners.set(
        event,
        arr.filter((f) => f !== fn),
      );
  }
}

用起来:

js 复制代码
const bus = new Emitter();
bus.on("login", (user) => console.log(user.name, "登录了"));
bus.emit("login", { name: "小不" }); // 小不 登录了

坑在哪 :忘记 off 是内存泄漏的元凶。Vue/React 组件销毁时记得解绑,或者直接用 mitt / tiny-emitter 这类库省心。


9. Proxy 模式:比 Object.freeze 灵活的"只读视图"

Object.freeze 是死板的,要么全冻要么全不冻。Proxy 可以做更细的拦截:

js 复制代码
function readonly(obj) {
  return new Proxy(obj, {
    set(target, key, value) {
      throw new Error(`属性 ${key} 不可写`);
    },
    deleteProperty(target, key) {
      throw new Error(`属性 ${key} 不可删`);
    },
  });
}

const config = readonly({ api: "https://..." });
config.api = "x"; // Error: 属性 api 不可写

坑在哪 :Proxy 不会真正冻结原对象,readonly(config).api = 'x' 报错,但 config.api = 'x' 还是能改。深只读要递归包一层。


10. 装饰器模式:函数版 AOP

想在不修改原函数的前提下,加日志 / 计时 / 鉴权?

js 复制代码
function withLog(fn) {
  return function (...args) {
    console.log("调用:", fn.name, args);
    const result = fn(...args);
    console.log("返回:", result);
    return result;
  };
}

const add = withLog((a, b) => a + b);
add(1, 2); // 调用: add [1, 2]  返回: 3

ES 装饰器提案快落地了,TS 早就能用,但函数包装写法兼容性更好,老项目也能上。

坑在哪 :装饰器会把原函数 name 改了(withLog((a, b) => ...) 拿不到原名),调试时栈追踪会丢名字,记得手动设 .name


📦 收个尾

这 10 个技巧浓缩一下:

  • 最高频踩坑?.&& 混用、?? 误用 ||structuredClone 浅拷贝、catch 吞错
  • 最值得收藏 :策略模式查表演示、Object.prototype.toString.call() 终极大法
  • 核心思路:能让语言帮你干的,别自己手写

学到了就是赚到了,犹豫徘徊等于白来~


写到最后

想要啥技巧?评论区甩个题目过来~

  • 你刚踩的坑
  • 项目里反复写的代码
  • 想搞清楚但一直懒得查的 API

小不看到...不一定回 😂 毕竟代码里翻车太多,腾不出手~

Ps:三连随缘,催更的会被打 😂

相关推荐
@@@@@@@@541 小时前
JavaScript 的缺点与 TypeScript 的弥补
开发语言·javascript·typescript
Hilaku1 小时前
为什么业务型前端容易遭遇中年危机?
前端·javascript·程序员
এ慕ོ冬℘゜1 小时前
深度解析 JavaScript:赋予 Web 灵魂的“全栈语言”
开发语言·前端·javascript
iCOD3R1 小时前
Skill - 3秒生成精美GitHub主页
前端·程序员·ai编程
Mr_凌宇1 小时前
# AI 应用工程入门学习笔记 一
人工智能·面试·程序员
爱勇宝1 小时前
《道德经》第5章:生产环境不相信眼泪
前端·后端·架构
掘金者阿豪1 小时前
LEFT JOIN 凭空消失的背后,是优化器偷偷帮你做了决定
前端·后端
HackTwoHub1 小时前
AntiDebug Mcp、AI逆向绕过前端,Hook 加密接口,抓取 Vue 路由漏洞,接入 MCP 让 AI 自动化挖掘前端漏洞
前端·vue.js·人工智能·安全·web安全·网络安全·系统安全
Mr_凌宇1 小时前
AI 应用工程进阶扩展学习笔记 二
前端·面试