原生 JavaScript 方法实战指南

原生 JavaScript 方法实战指南

平时开发中经常用到各种 JS 方法,但有些细节老是记不住,踩过不少坑。整理了这份笔记,记录一下常用方法的实际用法和注意事项。

数组方法

map() - 最常用的数组转换

日常开发中用得最多的方法之一,把数组每个元素都处理一下:

javascript 复制代码
// 最基本的用法
const numbers = [1, 2, 3, 4];
const doubled = numbers.map((n) => n * 2);
console.log(doubled); // [2, 4, 6, 8]

// 处理对象数组,这个场景很常见
const users = [
  { id: 1, name: 'John', age: 25 },
  { id: 2, name: 'Jane', age: 30 },
];

// 提取特定字段
const names = users.map((user) => user.name);
console.log(names); // ['John', 'Jane']

// 添加新属性
const usersWithStatus = users.map((user) => ({
  ...user,
  isAdult: user.age >= 18,
}));

注意事项:

  • map 不会改变原数组
  • 如果不 return 任何值,结果数组中对应位置就是 undefined
  • 稀疏数组的空位会被跳过
javascript 复制代码
// 这个坑我踩过
const arr = [1, 2, 3];
const result = arr.map((n) => {
  console.log(n); // 会打印,但没有 return
});
console.log(result); // [undefined, undefined, undefined]

filter() - 筛选数据

经常用来过滤数组数据:

javascript 复制代码
// 基本用法
const ages = [15, 18, 21, 25, 30];
const adults = ages.filter((age) => age >= 18);
console.log(adults); // [18, 21, 25, 30]

// 过滤对象数组
const products = [
  { name: '苹果', price: 5, inStock: true },
  { name: '香蕉', price: 3, inStock: false },
  { name: '橘子', price: 4, inStock: true },
];

const availableProducts = products.filter((p) => p.inStock && p.price > 3);
console.log(availableProducts); // [{ name: '苹果', price: 5, inStock: true }, { name: '橘子', price: 4, inStock: true }]

// 去重(结合 indexOf)
const duplicates = [1, 2, 2, 3, 3, 4];
const unique = duplicates.filter(
  (item, index) => duplicates.indexOf(item) === index
);
console.log(unique); // [1, 2, 3, 4]

find() 和 findIndex()

find() 找到第一个符合条件的元素:

javascript 复制代码
const users = [
  { id: 1, name: 'John', email: 'john@example.com' },
  { id: 2, name: 'Jane', email: 'jane@example.com' },
];

// 根据 ID 查找用户
const user = users.find((u) => u.id === 2);
console.log(user); // { id: 2, name: 'Jane', email: 'jane@example.com' }

// 找不到返回 undefined
const notFound = users.find((u) => u.id === 999);
console.log(notFound); // undefined

// findIndex() 返回索引
const userIndex = users.findIndex((u) => u.name === 'Jane');
console.log(userIndex); // 1

reduce() - 最强大也是最容易搞混的

刚开始学的时候老是搞不懂,多练几次就好了:

javascript 复制代码
// 最简单的累加
const numbers = [1, 2, 3, 4, 5];
const sum = numbers.reduce((acc, curr) => acc + curr, 0);
console.log(sum); // 15

// 找最大值
const max = numbers.reduce((acc, curr) => Math.max(acc, curr));
console.log(max); // 5

// 统计出现次数
const fruits = ['apple', 'banana', 'apple', 'orange', 'banana'];
const count = fruits.reduce((acc, fruit) => {
  acc[fruit] = (acc[fruit] || 0) + 1;
  return acc;
}, {});
console.log(count); // { apple: 2, banana: 2, orange: 1 }

// 数组转对象(经常用到)
const users = [
  { id: 1, name: 'John' },
  { id: 2, name: 'Jane' },
];
const userMap = users.reduce((acc, user) => {
  acc[user.id] = user;
  return acc;
}, {});
console.log(userMap); // { 1: { id: 1, name: 'John' }, 2: { id: 2, name: 'Jane' } }

forEach() vs for 循环

forEach 写起来简洁,但有些限制:

javascript 复制代码
const numbers = [1, 2, 3, 4, 5];

// 基本用法
numbers.forEach((num, index) => {
  console.log(`索引 ${index}: ${num}`);
});

// 注意:forEach 不能用 break 或 continue
// 这样会报错
numbers.forEach((num) => {
  if (num === 3) {
    // break; // SyntaxError!
    return; // 这个只会跳过当前迭代,类似 continue
  }
  console.log(num);
});

// 如果需要中途退出,用 for 循环或 some/every
for (let num of numbers) {
  if (num === 3) break; // 这样才行
  console.log(num);
}

some() 和 every()

检查数组条件的好帮手:

javascript 复制代码
const ages = [16, 18, 20, 22];

// some(): 有一个满足就返回 true
const hasAdult = ages.some((age) => age >= 18);
console.log(hasAdult); // true

// every(): 全部满足才返回 true
const allAdults = ages.every((age) => age >= 18);
console.log(allAdults); // false

// 实际应用:表单验证
const formFields = [
  { name: 'email', value: 'test@example.com', required: true },
  { name: 'name', value: '', required: true },
  { name: 'phone', value: '123456', required: false },
];

const hasEmptyRequired = formFields.some(
  (field) => field.required && !field.value
);
console.log(hasEmptyRequired); // true (name 字段为空)

字符串方法

split() 和 join()

处理字符串分割和拼接:

javascript 复制代码
// 基本分割
const str = 'apple,banana,orange';
const fruits = str.split(',');
console.log(fruits); // ['apple', 'banana', 'orange']

// 限制分割数量
const limited = str.split(',', 2);
console.log(limited); // ['apple', 'banana']

// 处理路径
const path = '/user/profile/edit';
const segments = path.split('/').filter(Boolean); // 过滤空字符串
console.log(segments); // ['user', 'profile', 'edit']

// join() 拼接回去
const joined = fruits.join(' | ');
console.log(joined); // 'apple | banana | orange'

// 常用技巧:数组去重后拼接
const tags = ['js', 'react', 'js', 'vue', 'react'];
const uniqueTags = [...new Set(tags)].join(', ');
console.log(uniqueTags); // 'js, react, vue'

includes() 和 indexOf()

字符串搜索方法:

javascript 复制代码
const text = 'Hello JavaScript World';

// includes() 返回布尔值,更语义化
console.log(text.includes('JavaScript')); // true
console.log(text.includes('Python')); // false

// indexOf() 返回位置,-1 表示没找到
console.log(text.indexOf('JavaScript')); // 6
console.log(text.indexOf('Python')); // -1

// 从指定位置开始搜索
console.log(text.indexOf('o', 5)); // 15 (从位置5开始找)

// 实际应用:检查文件类型
const fileName = 'document.pdf';
const isPdf = fileName.includes('.pdf');
const isImage = ['.jpg', '.png', '.gif'].some((ext) => fileName.includes(ext));

slice()、substring()、substr()

字符串截取,这三个经常搞混:

javascript 复制代码
const str = 'Hello JavaScript';

// slice() - 最常用,支持负数
console.log(str.slice(0, 5)); // 'Hello'
console.log(str.slice(6)); // 'JavaScript'
console.log(str.slice(-10)); // 'JavaScript' (从倒数第10位开始)
console.log(str.slice(-10, -6)); // 'Java' (倒数第10到第6位)

// substring() - 不支持负数,负数当0处理
console.log(str.substring(0, 5)); // 'Hello'
console.log(str.substring(-5)); // 'Hello JavaScript' (负数当0处理)

// substr() - 已废弃,不建议使用
console.log(str.substr(6, 4)); // 'Java'

推荐只用 slice(),功能最全面。

trim()、padStart()、padEnd()

处理字符串空白和填充:

javascript 复制代码
// 去除空白
const messy = '  hello world  ';
console.log(messy.trim()); // 'hello world'
console.log(messy.trimStart()); // 'hello world  '
console.log(messy.trimEnd()); // '  hello world'

// 填充字符串 - 格式化数字时很有用
const num = 5;
console.log(num.toString().padStart(3, '0')); // '005'
console.log('5'.padEnd(10, '-')); // '5---------'

// 实际应用:格式化时间
function formatTime(hours, minutes) {
  const h = hours.toString().padStart(2, '0');
  const m = minutes.toString().padStart(2, '0');
  return `${h}:${m}`;
}
console.log(formatTime(9, 5)); // '09:05'

对象方法

Object.keys()、Object.values()、Object.entries()

遍历对象的好帮手:

javascript 复制代码
const user = {
  id: 1,
  name: 'John',
  email: 'john@example.com',
  age: 25,
};

// 获取所有键
const keys = Object.keys(user);
console.log(keys); // ['id', 'name', 'email', 'age']

// 获取所有值
const values = Object.values(user);
console.log(values); // [1, 'John', 'john@example.com', 25]

// 获取键值对数组
const entries = Object.entries(user);
console.log(entries); // [['id', 1], ['name', 'John'], ['email', 'john@example.com'], ['age', 25]]

// 实际应用:对象转换
const transformed = Object.entries(user).reduce((acc, [key, value]) => {
  acc[key.toUpperCase()] = value;
  return acc;
}, {});
console.log(transformed); // { ID: 1, NAME: 'John', EMAIL: 'john@example.com', AGE: 25 }

Object.assign() 和展开运算符

对象合并,现在更多用展开运算符:

javascript 复制代码
const defaults = { theme: 'light', fontSize: 14 };
const userSettings = { fontSize: 16, color: 'blue' };

// Object.assign() 方式
const merged1 = Object.assign({}, defaults, userSettings);
console.log(merged1); // { theme: 'light', fontSize: 16, color: 'blue' }

// 展开运算符(推荐)
const merged2 = { ...defaults, ...userSettings };
console.log(merged2); // { theme: 'light', fontSize: 16, color: 'blue' }

// 注意:都是浅拷贝
const user = {
  name: 'John',
  settings: { theme: 'dark' },
};
const copy = { ...user };
copy.settings.theme = 'light'; // 会影响原对象
console.log(user.settings.theme); // 'light'

hasOwnProperty() 和 in 运算符

检查对象属性:

javascript 复制代码
const user = { name: 'John', age: 25 };

// hasOwnProperty() 只检查自有属性
console.log(user.hasOwnProperty('name')); // true
console.log(user.hasOwnProperty('toString')); // false

// in 运算符检查包括继承的属性
console.log('name' in user); // true
console.log('toString' in user); // true

// 更安全的写法(避免对象重写 hasOwnProperty)
console.log(Object.prototype.hasOwnProperty.call(user, 'name')); // true

// 实际应用:安全地访问对象属性
function getValue(obj, key, defaultValue) {
  return obj.hasOwnProperty(key) ? obj[key] : defaultValue;
}

类型判断方法

typeof 和 instanceof

基本类型判断:

javascript 复制代码
// typeof 判断基本类型
console.log(typeof 'hello'); // 'string'
console.log(typeof 42); // 'number'
console.log(typeof true); // 'boolean'
console.log(typeof undefined); // 'undefined'
console.log(typeof null); // 'object' (这是个历史bug)
console.log(typeof {}); // 'object'
console.log(typeof []); // 'object'
console.log(typeof function () {}); // 'function'

// instanceof 判断对象类型
console.log([] instanceof Array); // true
console.log({} instanceof Object); // true
console.log(new Date() instanceof Date); // true

// 更准确的类型判断
function getType(value) {
  return Object.prototype.toString.call(value).slice(8, -1).toLowerCase();
}

console.log(getType([])); // 'array'
console.log(getType({})); // 'object'
console.log(getType(null)); // 'null'
console.log(getType(new Date())); // 'date'

Array.isArray()

专门判断数组:

javascript 复制代码
// 最可靠的数组判断方法
console.log(Array.isArray([])); // true
console.log(Array.isArray({})); // false
console.log(Array.isArray('hello')); // false

// 为什么不用 typeof
const arr = [];
console.log(typeof arr); // 'object' - 不准确

// 为什么不用 instanceof
// 在不同 iframe 中创建的数组,instanceof 可能返回 false

数学方法

Math 对象常用方法

javascript 复制代码
// 基本数学运算
console.log(Math.max(1, 5, 3)); // 5
console.log(Math.min(1, 5, 3)); // 1
console.log(Math.abs(-5)); // 5

// 四舍五入相关
console.log(Math.round(4.6)); // 5
console.log(Math.floor(4.9)); // 4 (向下取整)
console.log(Math.ceil(4.1)); // 5 (向上取整)

// 随机数
console.log(Math.random()); // 0-1 之间的随机数

// 实用的随机数函数
function randomInt(min, max) {
  return Math.floor(Math.random() * (max - min + 1)) + min;
}
console.log(randomInt(1, 10)); // 1-10 之间的随机整数

// 数组随机元素
function randomChoice(arr) {
  return arr[Math.floor(Math.random() * arr.length)];
}
const colors = ['red', 'blue', 'green'];
console.log(randomChoice(colors));

数字格式化

javascript 复制代码
const num = 1234.5678;

// toFixed() 保留小数位
console.log(num.toFixed(2)); // '1234.57'

// 注意:toFixed 返回字符串,且会四舍五入
console.log(typeof num.toFixed(2)); // 'string'

// parseInt() 和 parseFloat()
console.log(parseInt('123.45')); // 123
console.log(parseFloat('123.45')); // 123.45
console.log(parseInt('123abc')); // 123 (会忽略后面的字符)
console.log(parseInt('abc123')); // NaN

// 数字验证
function isValidNumber(value) {
  return !isNaN(value) && isFinite(value);
}
console.log(isValidNumber('123')); // true
console.log(isValidNumber('abc')); // false
console.log(isValidNumber(Infinity)); // false

日期方法

Date 对象基本操作

javascript 复制代码
// 创建日期
const now = new Date();
const specificDate = new Date('2023-12-25');
const timestamp = new Date(1640995200000);

// 获取日期部分
console.log(now.getFullYear()); // 2025
console.log(now.getMonth()); // 8 (注意:0-11)
console.log(now.getDate()); // 26
console.log(now.getDay()); // 4 (0=周日, 1=周一...)

// 获取时间部分
console.log(now.getHours()); // 14
console.log(now.getMinutes()); // 30
console.log(now.getSeconds()); // 45

// 时间戳
console.log(now.getTime()); // 毫秒时间戳
console.log(Date.now()); // 当前时间戳(静态方法)

// 实用函数:格式化日期
function formatDate(date) {
  const year = date.getFullYear();
  const month = (date.getMonth() + 1).toString().padStart(2, '0');
  const day = date.getDate().toString().padStart(2, '0');
  return `${year}-${month}-${day}`;
}
console.log(formatDate(new Date())); // '2025-09-26'

日期计算

javascript 复制代码
const now = new Date();

// 计算几天前/后
function addDays(date, days) {
  const result = new Date(date);
  result.setDate(result.getDate() + days);
  return result;
}

const tomorrow = addDays(now, 1);
const lastWeek = addDays(now, -7);

// 计算两个日期的差值
function daysBetween(date1, date2) {
  const diffTime = Math.abs(date2 - date1);
  const diffDays = Math.ceil(diffTime / (1000 * 60 * 60 * 24));
  return diffDays;
}

const start = new Date('2025-09-01');
const end = new Date('2025-09-26');
console.log(daysBetween(start, end)); // 25

常见坑点和注意事项

1. 数组方法的返回值

javascript 复制代码
const arr = [1, 2, 3];

// 这些方法不改变原数组,返回新数组
console.log(arr.map((x) => x * 2)); // [2, 4, 6]
console.log(arr.filter((x) => x > 1)); // [2, 3]
console.log(arr.slice(1)); // [2, 3]
console.log(arr); // [1, 2, 3] 原数组没变

// 这些方法会改变原数组
arr.push(4); // 返回新长度
arr.pop(); // 返回删除的元素
arr.sort(); // 返回排序后的数组(原数组也变了)
arr.reverse(); // 返回翻转后的数组(原数组也变了)

2. 类型转换陷阱

javascript 复制代码
// 字符串数字比较
console.log('2' > '10'); // true (字符串比较)
console.log(2 > 10); // false (数字比较)

// 数组转字符串
console.log([1, 2, 3].toString()); // '1,2,3'
console.log([1, 2, 3].join('')); // '123'

// 对象转字符串
console.log({}.toString()); // '[object Object]'
console.log(JSON.stringify({})); // '{}'

3. this 指向问题

javascript 复制代码
const obj = {
  name: 'Test',
  greet: function () {
    console.log(this.name);
  },
  delayedGreet: function () {
    setTimeout(function () {
      console.log(this.name); // undefined (this 指向 window)
    }, 1000);
  },
  delayedGreetArrow: function () {
    setTimeout(() => {
      console.log(this.name); // 'Test' (箭头函数保持 this)
    }, 1000);
  },
};

实际项目中的应用

数据处理管道

javascript 复制代码
// 处理 API 返回的用户数据
const rawUsers = [
  {
    id: 1,
    name: 'john doe',
    email: 'JOHN@EXAMPLE.COM',
    age: '25',
    active: 'true',
  },
  {
    id: 2,
    name: 'jane smith',
    email: 'jane@example.com',
    age: '30',
    active: 'false',
  },
];

const processedUsers = rawUsers
  .filter((user) => user.active === 'true') // 只要活跃用户
  .map((user) => ({
    ...user,
    name: user.name
      .split(' ')
      .map((word) => word.charAt(0).toUpperCase() + word.slice(1))
      .join(' '), // 首字母大写
    email: user.email.toLowerCase(), // 邮箱小写
    age: parseInt(user.age), // 转为数字
    active: user.active === 'true', // 转为布尔值
  }));

console.log(processedUsers);
// [{ id: 1, name: 'John Doe', email: 'john@example.com', age: 25, active: true }]

表单验证

javascript 复制代码
function validateForm(formData) {
  const errors = {};

  // 检查必填字段
  const requiredFields = ['name', 'email', 'password'];
  requiredFields.forEach((field) => {
    if (!formData[field] || !formData[field].toString().trim()) {
      errors[field] = `${field} 是必填项`;
    }
  });

  // 邮箱格式验证
  if (formData.email && !formData.email.includes('@')) {
    errors.email = '邮箱格式不正确';
  }

  // 密码长度验证
  if (formData.password && formData.password.length < 6) {
    errors.password = '密码长度不能少于6位';
  }

  return {
    isValid: Object.keys(errors).length === 0,
    errors,
  };
}

const result = validateForm({
  name: 'John',
  email: 'john@example.com',
  password: '12345',
});
console.log(result); // { isValid: false, errors: { password: '密码长度不能少于6位' } }

数据统计

javascript 复制代码
// 统计订单数据
const orders = [
  {
    id: 1,
    product: 'iPhone',
    price: 999,
    status: 'completed',
    date: '2025-09-01',
  },
  { id: 2, product: 'iPad', price: 599, status: 'pending', date: '2025-09-02' },
  {
    id: 3,
    product: 'iPhone',
    price: 999,
    status: 'completed',
    date: '2025-09-03',
  },
];

// 总收入(已完成订单)
const totalRevenue = orders
  .filter((order) => order.status === 'completed')
  .reduce((sum, order) => sum + order.price, 0);

// 产品销量统计
const productStats = orders
  .filter((order) => order.status === 'completed')
  .reduce((stats, order) => {
    stats[order.product] = (stats[order.product] || 0) + 1;
    return stats;
  }, {});

// 按状态分组
const ordersByStatus = orders.reduce((groups, order) => {
  if (!groups[order.status]) {
    groups[order.status] = [];
  }
  groups[order.status].push(order);
  return groups;
}, {});

console.log('总收入:', totalRevenue); // 1998
console.log('产品统计:', productStats); // { iPhone: 2 }
console.log('状态分组:', ordersByStatus);

性能优化小贴士

1. 避免不必要的数组操作

javascript 复制代码
// ❌ 不好的写法 - 多次遍历
const data = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
const result = data
  .filter((x) => x > 5)
  .map((x) => x * 2)
  .filter((x) => x < 20);

// ✅ 更好的写法 - 单次遍历
const betterResult = data.reduce((acc, x) => {
  if (x > 5) {
    const doubled = x * 2;
    if (doubled < 20) {
      acc.push(doubled);
    }
  }
  return acc;
}, []);

2. 合理使用缓存

javascript 复制代码
// 缓存复杂计算结果
const memoize = (fn) => {
  const cache = new Map();
  return (...args) => {
    const key = JSON.stringify(args);
    if (cache.has(key)) {
      return cache.get(key);
    }
    const result = fn(...args);
    cache.set(key, result);
    return result;
  };
};

const expensiveCalculation = memoize((n) => {
  console.log('计算中...');
  return n * n * n;
});

console.log(expensiveCalculation(5)); // 计算中... 125
console.log(expensiveCalculation(5)); // 125 (从缓存读取)

整理于 2025 年 9 月,实际项目踩坑总结

相关推荐
神龙斗士2402 小时前
Java 数组的定义与使用
java·开发语言·数据结构·算法
白露与泡影2 小时前
2025互联网大厂高频Java面试真题解析
java·开发语言·面试
蓝莓味的口香糖2 小时前
【企业微信】VUE项目在企微中自定义转发内容
前端·vue.js·企业微信
IT_陈寒2 小时前
告别低效!用这5个Python技巧让你的数据处理速度提升300% 🚀
前端·人工智能·后端
gopyer2 小时前
180课时吃透Go语言游戏后端开发2:Go语言中的变量
开发语言·游戏·golang·游戏后端开发
—Qeyser2 小时前
Laravel + UniApp AES加密/解密
前端·uni-app·laravel
月月吃喝2 小时前
【PyQt5】嵌套多线程数据交互实现
开发语言·qt·交互
C++chaofan2 小时前
游标查询在对话历史场景下的独特优势
java·前端·javascript·数据库·spring boot
cg.family2 小时前
Vue3 v-slot 详解与示例
前端·javascript·vue.js