JavaScript 核心知识笔记
侧边栏壁纸
  • 累计撰写 36 篇文章
  • 累计收到 1 条评论

JavaScript 核心知识笔记

ASN__
2026-04-03 / 0 评论 / 13 阅读 / 正在检测是否收录...

JavaScript 核心知识笔记

本文档整合了 Promise 异步、数组/对象核心方法、函数式编程、异步并发控制、不可变数据更新等企业级必备技巧。内容全面,示例丰富,可直接用于开发参考。

一、Promise 与异步基础

1.1 Promise 核心

// 创建异步任务
new Promise((resolve, reject) => { /* 异步操作 */ });

// 处理结果
promise.then(onFulfilled).catch(onRejected);

// 快速创建已决议的 Promise
Promise.resolve(value);
Promise.reject(error);

// 并发控制
Promise.all([p1, p2])   // 全部成功才成功,返回结果数组
Promise.race([p1, p2])  // 第一个完成的决定结果
Promise.allSettled()    // 等待全部结束,返回每个的状态
Promise.any()           // 第一个成功的决定结果

1.2 async/await 优雅语法

async function fetchData() {
  try {
    const result = await somePromise();
    // 直接拿到结果,不用写 then
  } catch (err) {
    // 错误处理
  }
}
// await 就是等 Promise 干完活,直接拿结果

二、数组核心处理函数(必会)

2.1 every – 全真才为真

// 表单校验:所有字段都通过校验
const formFields = [
  { name: 'username', valid: true },
  { name: 'email', valid: true },
  { name: 'phone', valid: false }
];
const isFormValid = formFields.every(field => field.valid);
// 场景:整体校验、权限全满足、批量数据合规检查

2.2 some – 一真即为真

const tasks = [
  { id: 1, name: '写文档', done: true },
  { id: 2, name: '改Bug', done: false }
];
const hasPendingTask = tasks.some(task => !task.done); // true

// 搜索命中
const keywords = '张三';
const hasMatch = users.some(user => user.name.includes(keywords));

2.3 filter – 筛选过滤(生成新数组)

const strings = ["苹果", "", "香蕉", " ", "橙子", null];
const validStrings = strings.filter(s => s && s.trim());
// 场景:数据筛选、清理无效项、数据分类

2.4 map – 一对一映射

// 字符串转数字
const strNums = ['1', '2', '3'];
const numbers = strNums.map(Number); // [1,2,3]

// 接口字段适配
const apiData = [{ user_name: '张三', user_age: 25 }];
const frontData = apiData.map(item => ({
  name: item.user_name,
  age: item.user_age
}));

2.5 reduce – 万能累加器

核心:把多个元素汇总成一个结果。必须返回累加器,必须传初始值!
// 求和
const sum = [1,2,3,4].reduce((acc, curr) => acc + curr, 0);

// 分组统计
const orderItems = [
  { category: '食品', price: 20 },
  { category: '服装', price: 100 },
  { category: '食品', price: 30 }
];
const totalByCategory = orderItems.reduce((acc, item) => {
  acc[item.category] = (acc[item.category] || 0) + item.price;
  return acc;
}, {}); // ← 初始值必须是 {}

// 场景:聚合统计、数据分组、数组转对象、函数式管道

2.6 find / findIndex – 精准查找

const users = [{ id: 1, name: '张三' }, { id: 2, name: '李四' }];
const user = users.find(u => u.id === 2);     // 返回元素
const index = users.findIndex(u => u.id === 2); // 返回索引,找不到 -1
// 与 indexOf 区别:支持复杂条件判断

2.7 flat & flatMap – 数组扁平化

const nested = [1, [2, [3, [4]]], 5];
nested.flat(Infinity); // [1,2,3,4,5]

// flatMap = map + flat(1)
const lines = ["Hello world", "JavaScript is good"];
const words = lines.flatMap(line => line.split(' '));
// ["Hello", "world", "JavaScript", "is", "good"]

2.8 includes – 是否包含

const roles = ['admin', 'editor'];
const isAdmin = roles.includes('admin');

2.9 sort – 排序(会修改原数组!)

const nums = [3,1,2];
// 不修改原数组的安全写法
const sorted = [...nums].sort((a,b) => a - b); // 升序
const desc = [...nums].sort((a,b) => b - a);   // 降序

2.10 reverse – 反转(会修改原数组)

const arr = [1,2,3];
const reversed = [...arr].reverse(); // [3,2,1]

2.11 slice – 截取(不改变原数组)

const arr = [1,2,3,4];
arr.slice(1);    // [2,3,4] 从索引1开始
arr.slice(1,3);  // [2,3]

2.12 splice – 删除/插入/替换(改变原数组)

const arr = [1,2,3];
arr.splice(1, 1);    // 从索引1删除1个 → [1,3]
arr.splice(1, 0, 99); // 插入 → [1,99,3]

三、对象核心处理函数

3.1 遍历三剑客:keys / values / entries

const obj = { a:1, b:2, c:3 };
Object.keys(obj);   // ['a','b','c']
Object.values(obj); // [1,2,3]
Object.entries(obj); // [['a',1], ['b',2], ['c',3]]

// 遍历替代 for...in,方便使用数组方法
Object.entries(obj).forEach(([key, value]) => {
  console.log(key, value);
});

3.2 Object.fromEntries – 键值对转回对象

// 过滤对象属性(只保留 name 和 age)
const obj = { name: '张三', age: 25, gender: '男' };
const picked = Object.fromEntries(
  Object.entries(obj).filter(([k]) => ['name','age'].includes(k))
);
// { name:'张三', age:25 }

// 对象转 URL 参数
const query = { name: '张三', age: 25 };
const search = new URLSearchParams(query).toString(); // name=张三&age=25

3.3 Object.assign – 浅拷贝与合并

const obj1 = { a:1 };
const obj2 = { b:2 };
const merged = Object.assign({}, obj1, obj2); // { a:1, b:2 }
// 等价于 { ...obj1, ...obj2 }

3.4 可选链 ?. 与空值合并 ??

// 安全访问深层属性
const user = { profile: { name: '张三' } };
console.log(user?.profile?.name);    // '张三'
console.log(user?.address?.city);    // undefined(不报错)

// 空值合并:只有 null/undefined 才用默认值
const count = 0;
console.log(count ?? 10);  // 0(不是 null/undefined,保留0)
console.log(count || 10);  // 10(因为0是假值,不推荐)

四、函数式编程高级技巧

4.1 函数组合(Pipe / Compose)

将多个函数串联成数据流水线,代码线性、可读性强。
// 从左到右执行(pipe,更符合人类阅读习惯)
const pipe = (...fns) => (initValue) => 
  fns.reduce((acc, fn) => fn(acc), initValue);

// 从右到左执行(compose,经典函数式)
const compose = (...fns) => (initValue) => 
  fns.reduceRight((acc, fn) => fn(acc), initValue);

// 实战:处理商品数据
const filterValid = (list) => list.filter(item => item.price > 0 && item.status === 1);
const mapField = (list) => list.map(({ goods_id: id, goods_name: name, price }) => ({ id, name, price }));
const sortByPrice = (list) => [...list].sort((a, b) => a.price - b.price);
const groupByPriceRange = (list) => list.reduce((acc, item) => {
  const range = item.price < 100 ? '低价' : item.price < 500 ? '中价' : '高价';
  acc[range] = [...(acc[range] || []), item];
  return acc;
}, {});

const processGoodsData = pipe(filterValid, mapField, sortByPrice, groupByPriceRange);
const result = processGoodsData(apiData);

4.2 柯里化(Currying)

将多参数函数拆分成单参数函数链,实现参数预置。
const curry = (fn) => (...args) =>
  args.length >= fn.length ? fn(...args) : curry(fn).bind(null, ...args);

// 用法示例
const add = (a, b, c) => a + b + c;
const curriedAdd = curry(add);
const add5 = curriedAdd(5);
console.log(add5(3, 2)); // 10
console.log(curriedAdd(1)(2)(3)); // 6

五、异步并发控制(手写限流调度器)

解决批量请求并发过高导致崩溃的问题。类似银行柜台:同时最多 limit 个任务在处理,其余排队。
/**
 * 异步并发限流
 * @param {Array<Function>} tasks 任务函数数组(每个任务返回 Promise)
 * @param {number} limit 最大并发数
 * @returns {Promise<any[]>} 所有任务结果数组(顺序与原任务一致)
 */
const asyncPool = async (tasks, limit = 3) => {
  const results = [];      // 存储所有结果(保持顺序)
  const running = [];      // 存储正在执行的任务 Promise

  for (let i = 0; i < tasks.length; i++) {
    const task = tasks[i];
    // 包装任务,确保它是一个 Promise
    const promise = Promise.resolve().then(() => task());
    results.push(promise); // 占位,顺序不变

    // 任务完成后从 running 中移除
    const finishPromise = promise.then(() => {
      const index = running.indexOf(finishPromise);
      if (index !== -1) running.splice(index, 1);
    });
    running.push(finishPromise);

    // 当并发数达到上限,等待任意一个任务完成
    if (running.length >= limit) {
      await Promise.race(running);
    }
  }

  // 等待所有任务完成
  return Promise.all(results);
};

// 使用示例
const createTask = (id, delay) => () => new Promise(resolve => {
  setTimeout(() => {
    console.log(`任务${id}完成`);
    resolve(id);
  }, delay);
});

const tasks = [
  createTask(1, 1000),
  createTask(2, 500),
  createTask(3, 800),
  createTask(4, 200),
  createTask(5, 600)
];

asyncPool(tasks, 2).then(results => console.log('全部结果', results));
// 同时最多2个任务在执行

六、复杂数据处理(树形结构)

6.1 扁平数据转树形(菜单/部门)

// 扁平数组,每个元素有 id, parentId
const flatList = [
  { id: 1, parentId: null, name: '根节点' },
  { id: 2, parentId: 1, name: '子节点A' },
  { id: 3, parentId: 1, name: '子节点B' },
  { id: 4, parentId: 2, name: '孙节点A1' }
];

function listToTree(list, parentId = null) {
  return list
    .filter(item => item.parentId === parentId)
    .map(item => ({ ...item, children: listToTree(list, item.id) }));
}

const tree = listToTree(flatList);

6.2 树形数据过滤(保留符合条件的节点及其祖先)

function filterTree(tree, predicate) {
  return tree
    .filter(node => predicate(node) || (node.children && filterTree(node.children, predicate).length))
    .map(node => ({ ...node, children: node.children ? filterTree(node.children, predicate) : [] }));
}

6.3 树形查找(findNode)

function findNode(tree, id) {
  for (const node of tree) {
    if (node.id === id) return node;
    if (node.children) {
      const found = findNode(node.children, id);
      if (found) return found;
    }
  }
  return null;
}

七、性能优化与不可变数据

7.1 记忆化(Memoization)

缓存函数执行结果,相同参数直接返回缓存,避免重复计算。
function memoize(fn) {
  const cache = new Map();
  return function(...args) {
    const key = JSON.stringify(args);
    if (cache.has(key)) return cache.get(key);
    const result = fn.apply(this, args);
    cache.set(key, result);
    return result;
  };
}

// 示例:斐波那契数列
const fib = memoize(n => {
  if (n < 2) return n;
  return fib(n - 1) + fib(n - 2);
});
console.log(fib(40)); // 速度极快

7.2 不可变数据更新(Immutable)

铁律:绝不修改原始对象/数组,所有修改都生成全新的对象/数组。
// 对象深层属性更新
const state = { user: { name: '张三', age: 25 }, loading: false };
const newState = {
  ...state,
  user: { ...state.user, age: 26 }  // 只修改 age
};

// 数组修改(map)
const todos = [{ id: 1, done: false }, { id: 2, done: true }];
const toggled = todos.map(todo =>
  todo.id === 1 ? { ...todo, done: true } : todo
);

// 数组删除(filter)
const withoutId1 = todos.filter(todo => todo.id !== 1);

// 数组新增(展开运算符)
const newTodo = { id: 3, done: false };
const added = [...todos, newTodo];

// 总结:
// - 改深层对象 → 用 ... 逐层展开
// - 改数组元素 → 用 map
// - 删数组元素 → 用 filter
// - 加数组元素 → 用 [...arr, newItem]

7.3 深拷贝方法

// 方法1:structuredClone(现代浏览器/Node 17+)
const clone = structuredClone(originalObject);

// 方法2:JSON 序列化(仅限纯数据,不含函数/undefined/循环引用)
const clone = JSON.parse(JSON.stringify(original));

// 方法3:Lodash(工业级最稳)
// const clone = _.cloneDeep(original);

八、全局错误捕获与边界

8.1 未捕获的 Promise 错误

window.addEventListener('unhandledrejection', event => {
  console.error('未处理的 Promise 错误:', event.reason);
  // 可上报日志或提示用户
});

8.2 同步代码错误捕获

window.addEventListener('error', event => {
  console.error('全局错误:', event.error);
  // 避免默认行为(如控制台报错仍保留)
  // return true 可阻止默认处理
});

8.3 异步函数的错误边界包装

// 高阶函数,自动捕获 async 函数错误
const safeAsync = (fn) => async (...args) => {
  try {
    return await fn(...args);
  } catch (err) {
    console.error('异步函数错误:', err);
    // 可返回默认值或 throw
    return null;
  }
};

// 使用
const fetchUser = safeAsync(async (id) => {
  const res = await fetch(`/user/${id}`);
  return res.json();
});

九、常用实战代码片段集锦

9.1 数组去重

const unique = [...new Set([1,2,2,3])]; // [1,2,3]

9.2 对象数组按字段去重

const uniqueByKey = (arr, key) => {
  const map = new Map();
  return arr.filter(item => !map.has(item[key]) && map.set(item[key], true));
};

9.3 批量重命名字段(解构 + 剩余运算符)

const renameKeys = (obj, keyMap) =>
  Object.fromEntries(
    Object.entries(obj).map(([k, v]) => [keyMap[k] || k, v])
  );

// 示例
const user = { user_id: 1, user_name: '张三' };
const renamed = renameKeys(user, { user_id: 'id', user_name: 'name' });
// { id:1, name:'张三' }

9.4 防抖(Debounce)与节流(Throttle)

// 防抖:连续触发只执行最后一次(搜索输入)
function debounce(fn, delay) {
  let timer;
  return function(...args) {
    clearTimeout(timer);
    timer = setTimeout(() => fn.apply(this, args), delay);
  };
}

// 节流:固定间隔执行一次(滚动/resize)
function throttle(fn, interval) {
  let last = 0;
  return function(...args) {
    const now = Date.now();
    if (now - last >= interval) {
      last = now;
      fn.apply(this, args);
    }
  };
}

十、总结速查表

需求方法
判断全部满足every
判断至少一个满足some
筛选数据filter
转换数据map
查找第一个元素find / findIndex
汇总统计reduce
数组去重[...new Set(arr)]
深拷贝structuredClone / JSON / lodash
对象遍历keys / values / entries
安全访问嵌套属性?.
空值默认??
函数组合流水线pipe / compose
参数预置curry
异步限流手写 asyncPool
扁平转树递归 filter + map
不可变更新... 展开、mapfilter
性能缓存memoize

最后叮嘱:Promise 是异步的地基,async/await 是漂亮的房子;数组/对象方法是日常开发的利剑;函数式组合让代码像诗一样流畅。熟记这些,足以应对大部分企业级开发场景。
0

评论

博主关闭了所有页面的评论