🔥 30 个 JavaScript 实用技巧:覆盖 80% 开发场景,效率狂飙!

82 阅读11分钟

🔥 30 个 JavaScript 实用技巧:覆盖 80% 开发场景,效率狂飙!

作为前端开发者,JavaScript 就像我们的 “瑞士军刀”—— 看似基础,却藏着无数能提升效率的 “隐藏技能”。很多时候,我们写的代码能跑通,但不够简洁;能实现功能,但不够优雅。

本文整理了 30 个高频实用的 JS 技巧,覆盖变量声明、数组操作、字符串处理、函数优化、异步编程等 8 大场景,每个技巧都附带 “普通写法 vs 优化写法” 对比和完整代码示例,新手能快速上手,老手能查漏补缺~

一、变量声明与赋值(3 个技巧)

1. 多变量快速赋值(解构赋值进阶)

javascript

// ❌ 普通写法:重复赋值,代码冗余
let a = 1;
let b = 2;
let c = 3;

// ✅ 优化写法:数组解构快速赋值
const [a, b, c] = [1, 2, 3];

// 🌟 进阶:交换变量(无需临时变量)
[a, b] = [b, a]; // a=2, b=1

// 🌟 进阶:对象解构赋值(提取接口返回数据)
const { name, age, address = '未知' } = userInfo; // 缺省值兜底

2. 变量默认值(优雅处理 undefined)

javascript

// ❌ 普通写法:三元运算符繁琐
const username = params.username ? params.username : '游客';

// ✅ 优化写法:逻辑或运算符(简洁)
const username = params.username || '游客';

// ✅ 更严谨:空值合并运算符(仅当值为null/undefined时生效)
const username = params.username ?? '游客'; 
// 区别:''、0、false不会触发默认值,更符合实际场景

3. 常量声明(const 优先,let 兜底)

javascript

// ❌ 不推荐:变量不会修改却用let
let PI = 3.14159;
PI = 3.14; // 无意修改,不会报错

// ✅ 优化写法:不会修改的变量用const(只读保护)
const PI = 3.14159;
PI = 3.14; // 报错:Assignment to constant variable

二、数组操作(7 个技巧,开发高频!)

4. 数组去重(3 种场景全覆盖)

javascript

// 场景1:简单数组去重(数字/字符串)
const arr = [1, 2, 2, 3, 3, 3];
// ✅ 优化写法:Set+扩展运算符(简洁高效)
const uniqueArr = [...new Set(arr)]; // [1,2,3]

// 场景2:对象数组去重(根据id去重)
const objArr = [{id:1,name:'a'}, {id:2,name:'b'}, {id:1,name:'a'}];
// ✅ 优化写法:Map键值对去重
const uniqueObjArr = Array.from(
  new Map(objArr.map(item => [item.id, item])).values()
);

// 场景3:超大数组去重(性能优先)
const bigArr = new Array(100000).fill(0).map((_,i) => i%1000);
// ✅ 优化写法:对象哈希表(O(n)时间复杂度)
const uniqueBigArr = (() => {
  const map = {};
  return bigArr.filter(item => !map[item] && (map[item] = true));
})();

5. 数组扁平化(多维数组转一维)

javascript

const nestedArr = [1, [2, [3, [4]]]];

// ✅ 技巧1:flat(depth)(简洁,depth为扁平化深度)
const flatArr1 = nestedArr.flat(Infinity); // [1,2,3,4](Infinity表示无限深度)

// ✅ 技巧2:递归+concat(兼容性好)
function flattenArr(arr) {
  return arr.reduce((acc, item) => 
    acc.concat(Array.isArray(item) ? flattenArr(item) : item), []
  );
}
const flatArr2 = flattenArr(nestedArr);

6. 数组过滤 + 映射(链式调用高效处理)

javascript

const data = [
  {name:'张三', age:18, score:80},
  {name:'李四', age:20, score:60},
  {name:'王五', age:19, score:90}
];

// 需求:筛选分数≥80的用户,只保留name和score字段
// ❌ 普通写法:两次遍历(效率低)
const filtered = data.filter(item => item.score ≥80);
const result = filtered.map(item => ({name: item.name, score: item.score}));

// ✅ 优化写法:reduce一次遍历(性能更优)
const result = data.reduce((acc, item) => {
  if (item.score ≥80) {
    acc.push({name: item.name, score: item.score});
  }
  return acc;
}, []);

7. 数组查找(按需选择高效方法)

javascript

const users = [
  {id:1, name:'张三'},
  {id:2, name:'李四'},
  {id:3, name:'王五'}
];

// 场景1:查找第一个匹配项(返回对象)
// ✅ find()(找到即停止,效率高)
const user = users.find(item => item.id === 2); // {id:2, name:'李四'}

// 场景2:查找匹配项的索引
// ✅ findIndex()(直接返回索引,无需手动遍历)
const userIndex = users.findIndex(item => item.id === 2); // 1

// 场景3:判断数组是否包含某个值
// ✅ includes()(简洁,支持基本类型)
const hasUser = users.some(item => item.id === 2); // true(对象数组用some)
const hasNum = [1,2,3].includes(2); // true(基本类型用includes)

8. 数组排序(自定义排序规则)

javascript

const arr = [3, 1, 4, 1, 5, 9];

// ✅ 数字升序/降序
const ascArr = arr.sort((a, b) => a - b); // [1,1,3,4,5,9]
const descArr = arr.sort((a, b) => b - a); // [9,5,4,3,1,1]

// ✅ 对象数组排序(按age升序,age相同按name降序)
const userArr = [  {name:'张三', age:20},  {name:'李四', age:18},  {name:'王五', age:20}];
const sortedUserArr = userArr.sort((a, b) => {
  if (a.age !== b.age) return a.age - b.age;
  return b.name.localeCompare(a.name); // 中文排序用localeCompare
});

9. 数组拼接与截取(不修改原数组)

javascript

const arr1 = [1,2,3];
const arr2 = [4,5,6];

// ❌ 不推荐:push/splice会修改原数组
arr1.push(...arr2); // arr1变成[1,2,3,4,5,6]

// ✅ 优化写法:扩展运算符/concat(纯函数,不修改原数组)
const newArr = [...arr1, ...arr2]; // [1,2,3,4,5,6]
const newArr2 = arr1.concat(arr2); // 同上

// ✅ 数组截取(slice不修改原数组,splice会修改)
const arr = [1,2,3,4,5];
const subArr = arr.slice(1, 3); // [2,3](原数组不变)

10. 数组空值过滤(清理无效数据)

javascript

const dirtyArr = [1, null, undefined, '', 0, false, NaN, 2];

// ✅ 过滤所有空值(null/undefined/''/NaN)
const cleanArr = dirtyArr.filter(Boolean); // [1,0,false,2]
// 注意:0和false会被保留,若需过滤可自定义:
const strictCleanArr = dirtyArr.filter(item => 
  item !== null && item !== undefined && item !== '' && !isNaN(item)
);

三、字符串处理(5 个技巧)

11. 字符串模板(优雅拼接字符串)

javascript

const name = '张三';
const age = 18;
const score = 90;

// ❌ 普通写法:字符串拼接繁琐,易出错
const info = '姓名:' + name + ',年龄:' + age + ',分数:' + score;

// ✅ 优化写法:模板字符串(支持换行和表达式)
const info = `姓名:${name},年龄:${age},分数:${score},等级:${score≥90?'优秀':'良好'}`;

// 🌟 进阶:多行字符串(无需\n换行符)
const html = `
  <div class="user-card">
    <h3>${name}</h3>
    <p>年龄:${age}</p>
  </div>
`;

12. 字符串截取(根据需求选择方法)

javascript

const str = 'Hello, JavaScript!';

// 场景1:从索引n开始截取到末尾
const sub1 = str.slice(7); // 'JavaScript!'(推荐,支持负数索引)
const sub2 = str.substring(7); // 同上,但不支持负数

// 场景2:截取前n个字符
const sub3 = str.slice(0, 5); // 'Hello'

// 场景3:从末尾截取n个字符(负数索引)
const sub4 = str.slice(-11); // 'JavaScript!'

13. 字符串去空格(前后 / 所有空格)

javascript

const str = '  Hello JavaScript  ';

// ✅ 去除前后空格(常用)
const trimStr = str.trim(); // 'Hello JavaScript'

// ✅ 去除所有空格(包括中间)
const noSpaceStr = str.replace(/\s+/g, ''); // 'HelloJavaScript'

// ✅ 去除开头空格
const trimStartStr = str.trimStart(); // 'Hello JavaScript  '

// ✅ 去除结尾空格
const trimEndStr = str.trimEnd(); // '  Hello JavaScript'

14. 字符串大小写转换(快速处理)

javascript

const str = 'Hello JavaScript';

// ✅ 全部大写
const upperStr = str.toUpperCase(); // 'HELLO JAVASCRIPT'

// ✅ 全部小写
const lowerStr = str.toLowerCase(); // 'hello javascript'

// ✅ 首字母大写(其余小写)
const capitalizeStr = str.charAt(0).toUpperCase() + str.slice(1).toLowerCase();

15. 字符串是否包含某个字符(简洁判断)

javascript

const str = 'Hello, JavaScript!';

// ❌ 普通写法:indexOf判断(不直观)
const hasJs = str.indexOf('JavaScript') !== -1;

// ✅ 优化写法:includes()(语义化清晰)
const hasJs = str.includes('JavaScript'); // true

// ✅  startsWith/endsWith(判断开头/结尾)
const startsWithHello = str.startsWith('Hello'); // true
const endsWithExclamation = str.endsWith('!'); // true

四、函数优化(4 个技巧)

16. 函数默认参数(避免 undefined 报错)

javascript

// ❌ 普通写法:函数内判断默认值
function calculate(a, b) {
  a = a || 0;
  b = b || 0;
  return a + b;
}

// ✅ 优化写法:参数默认值(简洁,语义化)
function calculate(a = 0, b = 0) {
  return a + b;
}

calculate(2); // 2+0=2
calculate(); // 0+0=0

17. 箭头函数(简洁写法,绑定 this)

javascript

// ❌ 普通写法:函数表达式繁琐
const add = function(a, b) {
  return a + b;
};

// ✅ 优化写法:箭头函数(单表达式可省略return和{})
const add = (a, b) => a + b;

// 🌟 注意:箭头函数不绑定this,适合非方法函数
const user = {
  name: '张三',
  sayHi: () => {
    console.log(`Hi, ${this.name}`); // this指向外部作用域,非user对象
  }
};
// 方法函数仍用普通函数:
const user = {
  name: '张三',
  sayHi() {
    console.log(`Hi, ${this.name}`); // 正确:Hi, 张三
  }
};

18. 函数柯里化(复用逻辑,延迟执行)

javascript

// 需求:实现add(1)(2)(3) = 6
// ✅ 柯里化函数
function curry(fn) {
  return function curried(...args) {
    // 当参数数量足够时,执行原函数
    if (args.length >= fn.length) {
      return fn.apply(this, args);
    }
    // 否则返回新函数,接收剩余参数
    return function(...nextArgs) {
      return curried.apply(this, args.concat(nextArgs));
    };
  };
}

// 使用:
const add = curry((a, b, c) => a + b + c);
add(1)(2)(3); // 6
add(1, 2)(3); // 6

19. 防抖与节流(性能优化必备)

javascript

// ✅ 防抖:触发后延迟n秒执行,重复触发则重新计时(适合搜索框输入)
function debounce(fn, delay = 300) {
  let timer;
  return function(...args) {
    clearTimeout(timer);
    timer = setTimeout(() => {
      fn.apply(this, args);
    }, delay);
  };
}

// ✅ 节流:n秒内只执行一次(适合滚动、resize事件)
function throttle(fn, interval = 500) {
  let lastTime = 0;
  return function(...args) {
    const now = Date.now();
    if (now - lastTime >= interval) {
      fn.apply(this, args);
      lastTime = now;
    }
  };
}

// 使用示例:
const search = debounce((keyword) => {
  console.log('搜索:', keyword);
}, 500);

window.addEventListener('scroll', throttle(() => {
  console.log('滚动事件触发');
}, 1000));

五、对象操作(4 个技巧)

20. 对象合并(避免修改原对象)

javascript

const obj1 = {a:1, b:2};
const obj2 = {b:3, c:4};

// ❌ 普通写法:Object.assign(浅拷贝,会修改原对象)
Object.assign(obj1, obj2); // obj1变成{a:1, b:3, c:4}

// ✅ 优化写法:扩展运算符(纯函数,不修改原对象)
const mergedObj = {...obj1, ...obj2}; // {a:1, b:3, c:4}

// ✅ 深拷贝合并(对象嵌套时使用)
const deepObj1 = {a:1, b: {c:2}};
const deepObj2 = {b: {d:3}, e:4};
const deepMergedObj = JSON.parse(JSON.stringify({...deepObj1, ...deepObj2}));
// 复杂场景推荐用lodash.cloneDeep

21. 对象属性遍历(按需选择方法)

javascript

const user = {id:1, name:'张三', age:18};

// ✅ 遍历键名
const keys = Object.keys(user); // ['id','name','age']

// ✅ 遍历值
const values = Object.values(user); // [1,'张三',18]

// ✅ 遍历键值对
const entries = Object.entries(user); 
// [[1,'id'], ['张三','name'], [18,'age']]

// ✅ 遍历所有属性(包括继承属性)
for (const key in user) {
  if (user.hasOwnProperty(key)) { // 过滤继承属性
    console.log(`${key}: ${user[key]}`);
  }
}

22. 对象属性判断(简洁方法)

javascript

const user = {id:1, name:'张三', age:18};

// ❌ 普通写法:判断属性是否存在(易出错)
const hasName = user.name !== undefined; // 若属性值为undefined,会误判

// ✅ 优化写法:hasOwnProperty(判断自身属性)
const hasName = user.hasOwnProperty('name'); // true

// ✅ 更推荐:Object.prototype.hasOwnProperty.call(避免原型污染)
const hasName = Object.prototype.hasOwnProperty.call(user, 'name');

// ✅ 简单场景:in运算符(包括继承属性)
const hasToString = 'toString' in user; // true(继承自Object.prototype)

23. 对象解构赋值(提取属性高效)

javascript

const user = {
  id:1,
  name:'张三',
  address: {
    province: '广东',
    city: '深圳'
  }
};

// ✅ 提取顶层属性
const {id, name} = user;

// ✅ 提取嵌套属性
const {address: {city}} = user; // city='深圳'

// ✅ 重命名属性(避免变量名冲突)
const {name: username} = user; // username='张三'

// ✅ 缺省值(属性不存在时使用默认值)
const {gender = '男'} = user; // gender='男'

六、异步编程(3 个技巧)

24. Promise 并发控制(避免请求过多)

javascript

// 需求:同时请求10个接口,限制最多3个并发
const urls = new Array(10).fill(0).map((_,i) => `/api/data/${i}`);

// ✅ 并发控制函数
async function requestWithLimit(urls, limit) {
  const results = [];
  const executing = []; // 存储正在执行的请求

  for (const url of urls) {
    const promise = fetch(url).then(res => res.json());
    results.push(promise);

    // 当并发数达到限制,等待其中一个完成
    if (promise.length >= limit) {
      await Promise.race(executing);
    }

    // 将请求添加到执行队列,完成后移除
    const execute = promise.then(() => {
      executing.splice(executing.indexOf(execute), 1);
    });
    executing.push(execute);
  }

  return Promise.all(results);
}

// 使用:
requestWithLimit(urls, 3).then(data => console.log('所有请求结果:', data));

25. async/await 错误处理(优雅捕获)

javascript

// ❌ 普通写法:多个await重复try/catch(冗余)
async function fetchData() {
  try {
    const user = await fetchUser();
  } catch (err) {
    console.error('用户数据请求失败:', err);
  }
  try {
    const products = await fetchProducts();
  } catch (err) {
    console.error('商品数据请求失败:', err);
  }
}

// ✅ 优化写法:封装to函数,统一处理错误
function to(promise) {
  return promise.then(data => [null, data]).catch(err => [err, null]);
}

async function fetchData() {
  const [userErr, user] = await to(fetchUser());
  if (userErr) return console.error('用户数据请求失败:', userErr);

  const [productsErr, products] = await to(fetchProducts());
  if (productsErr) return console.error('商品数据请求失败:', productsErr);
}

26. 异步循环(避免串行陷阱)

javascript

const ids = [1,2,3,4,5];

// ❌ 错误写法:串行执行,总耗时=5个请求之和
async function fetchSerial() {
  const results = [];
  for (const id of ids) {
    const data = await fetch(`/api/item/${id}`);
    results.push(data);
  }
  return results;
}

// ✅ 优化写法:并行执行,总耗时=最慢请求时间
async function fetchParallel() {
  const promises = ids.map(id => fetch(`/api/item/${id}`));
  const results = await Promise.all(promises);
  return results;
}

七、性能优化(3 个技巧)

27. 避免频繁 DOM 操作(批量处理)

javascript

// ❌ 普通写法:频繁操作DOM,导致重绘回流
const list = document.getElementById('list');
for (let i = 0; i < 1000; i++) {
  const li = document.createElement('li');
  li.textContent = `列表项 ${i}`;
  list.appendChild(li); // 每次append都会触发重绘
}

// ✅ 优化写法:DocumentFragment批量处理
const fragment = document.createDocumentFragment();
for (let i = 0; i < 1000; i++) {
  const li = document.createElement('li');
  li.textContent = `列表项 ${i}`;
  fragment.appendChild(li); // 先添加到文档片段,不触发重绘
}
list.appendChild(fragment); // 一次插入,只触发一次重绘

28. 缓存计算结果(避免重复计算)

javascript

// ❌ 普通写法:重复调用会重复计算(耗时)
function fibonacci(n) {
  if (n <= 1) return n;
  return fibonacci(n-1) + fibonacci(n-2);
}

// ✅ 优化写法:闭包缓存计算结果(记忆化)
const fibonacci = (() => {
  const cache = {}; // 缓存已计算结果
  return function fib(n) {
    if (n <= 1) return n;
    if (cache[n]) return cache[n]; // 命中缓存,直接返回
    cache[n] = fib(n-1) + fib(n-2); // 计算后缓存
    return cache[n];
  };
})();

fibonacci(10); // 第一次计算,缓存结果
fibonacci(10); // 直接从缓存获取,速度极快

29. 避免使用 eval(安全 + 性能)

javascript

const a = 1;
const b = 2;

// ❌ 不推荐:eval执行字符串,安全风险+性能差
const result = eval('a + b');

// ✅ 优化写法:使用Function构造函数(相对安全)
const result = new Function('a', 'b', 'return a + b')(a, b);

// 🌟 更推荐:直接计算(除非动态执行不可避免)
const result = a + b;

八、边界处理与调试(2 个技巧)

30. 类型判断(精准判断数据类型)

javascript

// ❌ 普通写法:typeof判断不准确(数组/对象都返回object)
typeof []; // 'object'
typeof {}; // 'object'

// ✅ 优化写法:Object.prototype.toString.call(精准)
function getType(data) {
  return Object.prototype.toString.call(data).slice(8, -1).toLowerCase();
}

getType([]); // 'array'
getType({}); // 'object'
getType(''); // 'string'
getType(123); // 'number'
getType(null); // 'null'
getType(undefined); // 'undefined'
getType(Symbol('a')); // 'symbol'

31. 调试技巧(console 高级用法)

javascript

const user = {id:1, name:'张三', age:18};
const arr = [1,2,3,4,5];

// ✅ 1. 打印对象/数组(带展开功能)
console.log('用户信息:', user);
console.table(arr); // 表格形式打印数组(更直观)

// ✅ 2. 打印带标签的日志(区分不同日志)
console.log('%c用户信息', 'color: blue; font-size: 16px;', user);

// ✅ 3. 计时功能(测试代码执行时间)
console.time('循环耗时');
for (let i = 0; i < 100000; i++) {}
console.timeEnd('循环耗时'); // 输出:循环耗时: 0.5ms

// ✅ 4. 断言功能(条件不满足时报错)
console.assert(user.age >= 18, '用户年龄必须≥18');

结语:技巧是手段,优雅是目的 🚀

JavaScript 的这些技巧,本质上都是为了让代码更简洁、更高效、更易维护。但记住:没有最好的技巧,只有最适合场景的技巧

比如,箭头函数虽然简洁,但不能用于对象方法;扩展运算符虽然方便,但深拷贝时要注意嵌套对象。在实际开发中,要根据业务场景选择合适的写法,而不是盲目追求 “炫技”。

希望这 30 个技巧能帮你在日常开发中少写冗余代码,提升效率~ 你还有哪些珍藏的 JS 技巧?欢迎在评论区分享,点赞最高的技巧会被我补充到文章中!