JavaScript进阶学习


以下是针对 JavaScript 近年新特性的系统性学习文档,结合 ES6+ 核心特性与最新实践技巧整理而成:

一、基础语法

1.1 Lambda 表达式(箭头函数)

// 传统函数
const sum = function(a, b) { return a + b };

// 箭头函数简写
const sum = (a, b) => a + b;

​特性​:

Lambda表达式典型场景

// 数组操作(配合 map/filter)
const scores = [90, 85, 77];
const passed = scores.filter(score => score >= 80); // [90, 85]

// 异步回调
fetch('/api/data')
  .then(response => response.json())
  .then(data => console.log(data));

1.2 String的扩展方法

let name = '张三';
let strall = `姓名为:${name}`;
const sum = (a, b) => a + b;
let strsum = `12 + 32 为:${sum(12,32)}`;
let item = {"name": "张三", "age": 15, "sex": ""};
let str = `姓名:${item.name},年龄${item.age},性别:${item.sex}`;

1.3 String的其他方法

str.startsWith() 和 str.endsWith()

let name = '张三';
str.startsWith(''); // true
str.endsWith(''); // true

str.repeat()

let str = 'Hello';
str.repeat(3); // 'HelloHelloHello'

1.4 数组的基本方法

​修改原数组的方法​:pushpopunshiftshiftsplicesortreverse

​返回新数组的方法​:concatslicemapfilter

​ES5新增的迭代方法​:forEachmapfilterreducereduceRightsomeevery

const arr = [1, 2];
arr.push(3);      // arr → [1, 2, 3]
arr.pop();        // arr → [1, 2]
arr.unshift(0);   // arr → [0, 1, 2]
arr.shift();      // arr → [1, 2]

const a = [1, 2];
const b = a.concat(3, [4, 5]);  // b → [1, 2, 3, 4, 5]

const str = a.join("-");        // str → "1-2"

const c = [10, 20, 30, 40];
const sub = c.slice(1, 3);      // sub → [20, 30]

c.splice(1, 2, 99);             // c → [10, 99, 40]

1.5 Map的使用方法

const map = new Map();
map.set("age", 18).set(100, "分数"); // 链式调用

console.log(map.get("age")); // 18
console.log(map.has("gender")); // false
console.log(map.size); // 2
const map = new Map([
  ["a", 1],
  ["b", 2],
  ["c", 3]
]);

// 遍历键值对
map.forEach((value, key) => {
  console.log(key, value); // a 1, b 2, c 3
});

// 使用 for...of
for (const [key, value] of map) {
  console.log(key, value); // 同上
}

// 获取迭代器
console.log([...map.keys()]); // ["a", "b", "c"]
console.log([...map.values()]); // [1, 2, 3]

二、数组高阶方法

2.1 数组合并与拆解

let [a,b,c] = [11,22,33];
const arr1 = [1, 2, 3];
const arr2 = [3, 4, 5];
[...arr1, ...arr2]; // [1, 2, 3, 3, 4, 5]

let [arr3, ...rest] = [1, 2, 3, 4, 5];
arr3; // 1
rest; // [2, 3, 4, 5]
function sum(arg1, ...args) {
  console.log(arg1, args);
}
sum(1, 2, 3, 4, 5); // 1, [2, 3, 4, 5]

2.1 Array.map()

​用途​:映射数组元素生成新数组

const users = [{name: 'Alice'}, {name: 'Bob'}];
const names = users.map(user => user.name); // ['Alice', 'Bob']

2.2 Array.filter()

​用途​:条件筛选数组

const numbers = [1, 2, 3, 4];
const even = numbers.filter(n => n % 2 === 0); // [2, 4]

相当于数据库的where条件

const users = [{name: 'Alice',age: 25}, {name: 'Blind',age: 27}, {name: 'Bob',age: 30}, {name: 'Pongo',age: 30}];
const even = users.filter(user => user.age == 30);
字符串匹配
const originalArray = ["姓名","语文","班级","考号","总分","数学","物理","道法","道德","科学"];
// 使用正则表达式匹配 "语、数、英、道"
const result = originalArray.filter(str => /[语数英道理历生化]/.test(str));
console.log(result); // 把学科字段匹配出来

2.3 Array.flatMap()(ES2019)

​用途​:先映射后扁平化

const phrases = ["Hello world", "Goodbye moon"];
const words = phrases.flatMap(phrase => phrase.split(' ')); 
// ["Hello", "world", "Goodbye", "moon"]

2.4 Array.find() / Array.findIndex()

用于找出第一个符合条件的数组成员,如果没有找到返回undefined

const users = [{name: 'Alice',age: 25}, {name: 'Blind',age: 25}, {name: 'Bob',age: 30}];
const user = users.find(user => user.age === 25); // {name: 'Alice'}

用于找出第一个符合条件的数组成员的位置,如果没有找到返回-1

const users = [{name: 'Alice',age: 25}, {name: 'Blind',age: 27}, {name: 'Bob',age: 30}];;
const userIndex = users.findIndex(user => user.age > 28); //2

2.5 Array.includes()

表示某个数组是否包含给定的值,返回布尔值。

[1,2,3,4,5,6,7].includes(1); // true
[1,2,3,4,5,6,7].includes(10); // false
"hello".includes("el"); // true

2.5 Array.reduce()

let arr = [1, 2, 3, 4, 5];
let sum = arr.reduce(function (prev, cur, index, arr) {
    console.log(prev, cur, index);
    return prev + cur;
});
console.log('arr:', arr, 'sum:', sum); //sum=15
// 数组对象
const arr = [
    {id: 'a', value: 1},
    {id: 'b', value: 2},
    {id: 'c', value: 3}
];
// item是arr遍历出来的值
arr.reduce((sum, item) => {
    console.log(sum, item);
    return sum + item.value * 2; //返回给下一个your的值
},0); //给sum的初始值

2.6 Array.some() /

// Array.some() 极简使用笔记
// 核心功能​​:判断数组中 ​​是否至少有一个元素​​ 满足指定条件,一旦找到符合条件的元素,立即返回 true(停止遍历),若全部不满足,返回 false
// 示例数组
const numbers = [1, 3, 5, 7, 9];

// 检查是否存在偶数
const hasEven = numbers.some(n => n % 2 === 0); 
console.log(hasEven); // false

// 检查是否存在大于5的数
const hasBig = numbers.some(n => n > 5); 
console.log(hasBig); // true(7和9满足)

const users2 = [
    {name: 'Alice', active: true },
    {name: 'Bob', active: false }
];

const hasActiveUser = users2.some(user => user.active);
console.log(hasActiveUser); // true(Alice是active)

2.6 Array.every()

Array.every()方法用于检测数组中的所有元素是否都满足指定条件

const users = [
    { name: "Alice", age: 25 },
    { name: "Bob", age: 30 },
    { name: "Charlie", age: 18 }
];

// 检查所有用户是否都是成年人(age >= 18)
const allAdults = users.every(user => user.age >= 18);
console.log(allAdults); // true

2.7 Array.sort()(ES2019)

对象数组排序
const sortedStudents = [...students].sort((a, b) => 
    a.grade - b.grade || 
    a.class - b.class || 
    a.number - b.number
);
数字数组排序
const nums = [19,8,4,3,11,67,2].sort((a, b) => a - b);
console.log(nums);

2.8 Array.from()(ES2019)

Array.from()方法用于将类数组对象(array-like)或可迭代对象(iterable)转换为真正的数组

// 示例 3: 转换 Set 为数组
const set = new Set([1, 2, 3]);
const arrayFromSet = Array.from(set);
console.log(arrayFromSet); // [1, 2, 3]

// 示例 4: 转换字符串为字符数组
const str = "hello";
const chars = Array.from(str);
console.log(chars); // ['h', 'e', 'l', 'l', 'o']

// 示例 6: 转换 NodeList 并提取 id
const elements = document.querySelectorAll(".item");
const ids = Array.from(elements, el => el.id);
console.log(ids); // 所有元素的 id 数组

2.9 Array.of()(ES2019)

2.10 Array.copyWithin()(ES2019)

三、对象操作增强

3.1 展开运算符

const user = { name: 'Alice', age: 25 };
const updatedUser = { ...user, age: 26 }; // 合并并覆盖属性

3.2 Object.keys()

let user = { name: 'Alice', age: 18, sex: '', address: 'Beijing'};
Object.keys(user); // ["name", "age", "sex", "address"]

3.3 Object.values()

let user = { name: 'Alice', age: 18, sex: '', address: 'Beijing'};
Object.values(user); // ["Alice", 18, "男", "Beijing"]

3.4 Object.entries()

​用途​:对象键值遍历

const person = { name: 'Bob', age: 30 };
Object.entries(person).forEach(([key, val]) => {
  console.log(`${key}: ${val}`); // "name: Bob", "age: 30"
});

四、类与模块化(ES6+)

4.1 类语法增强

class Player {
  #score = 0; // 私有字段(ES2022)[1](@ref)
  
  constructor(name) { this.name = name; }

  // Getter/Setter
  get score() { return this.#score; }
  addPoints(points) { this.#score += points; }
}

const player = new Player('Alice');
player.addPoints(10);
console.log(player.score); // 10(无法直接访问 #score)

4.2 模块化(ES Modules)

// math.js
export const PI = 3.14;
export function sum(a, b) { return a + b; }

// app.js
import { PI, sum } from './math.js';
console.log(sum(PI, 2)); // 5.14

五、其他关键新特性

5.1 可选链操作符 ?.(ES2020)

const user = { address: { city: 'Beijing' } };
console.log(user?.address?.city); // "Beijing"
console.log(user?.contacts?.email); // undefined(不报错)

5.2 Nullish 合并 ??(ES2020)

const score = 0;
const displayScore = score ?? 'N/A'; // 0(|| 会误判 0 为假值)

5.3 Promise.allSettled()(ES2020)

const promises = [fetch('/api1'), fetch('/api2')];
Promise.allSettled(promises)
  .then(results => results.forEach(handleSuccessOrError));

六、实践笔记

## 学习日期:2025/04/16
## 箭头函数
- 适用场景:回调函数、数组方法
- 注意:避免在需要动态 `this` 的场景使用(如 DOM 事件处理器)

## 展开运算符
- 使用案例:合并对象 `{ ...defaults, ...userInput }`
- 注意:浅拷贝问题(嵌套对象需递归处理)

## 私有字段
- 语法:`#fieldName`
- 限制:仅类内部可访问,子类不可继承

6.1 统计及格人数和及格率

// 定义各科评分规则 (可动态配置)
const subjectConfig = {
  语文: { total: 150, pass: 90, high: 120 },
  数学: { total: 150, pass: 90, high: 135 },
  英语: { total: 120, pass: 72, high: 108 },
  化学: { total: 100, pass: 60, high: 85 },
  物理: { total: 100, pass: 60, high: 85 },
  历史: { total: 100, pass: 60, high: 85 },
  道法: { total: 100, pass: 60, high: 85 }
};

// 核心统计函数 (支持动态科目和规则)
function analyzeResults(students, subjectConfig) {
  const subjects = Object.keys(subjectConfig);
  
  // 初始化班级统计结构: Map<班级标识, 统计对象>
  const classStats = new Map();
  const globalStats = {
    total: 0,
    passAll: 0,
    highAny: 0,
    subjects: subjects.reduce((acc, subject) => ({
      ...acc,
      [subject]: { pass: 0, high: 0 }
    }), {})
  };

  // 遍历学生数据
  students.forEach(student => {
    // 生成班级唯一标识 (年级+班级)
    const classKey = `${student.年级}_${student.班级}`;
    // 动态初始化班级统计
    if (!classStats.has(classKey)) {
      classStats.set(classKey, {
        total: 0,
        passAll: 0,
        highAny: 0,
        subjects: subjects.reduce((acc, subject) => ({
          ...acc,
          [subject]: { pass: 0, high: 0 }
        }), {})
      });
    }
    const clsStats = classStats.get(classKey);
    
    // 更新计数
    clsStats.total++;
    globalStats.total++;

    // 核心判断逻辑
    let isAllPassed = true;
    let hasAnyHigh = false;
    
    subjects.forEach(subject => {
      const { pass, high } = subjectConfig[subject];
      const score = student[subject];
      
      // 判断单科是否及格
      const isPass = score >= pass;
      if (isPass) {
        clsStats.subjects[subject].pass++;
        globalStats.subjects[subject].pass++;
      } else {
        isAllPassed = false; // 存在一科不及格则全科不通过
      }
      
      // 判断单科是否高分
      const isHigh = score >= high;
      if (isHigh) {
        clsStats.subjects[subject].high++;
        globalStats.subjects[subject].high++;
        hasAnyHigh = true;
      }
    });

    // 更新全科/高分统计
    if (isAllPassed) {
      clsStats.passAll++;
      globalStats.passAll++;
    }
    if (hasAnyHigh) {
      clsStats.highAny++;
      globalStats.highAny++;
    }
  });

  // 计算比率
  const calculateRates = (stats) => ({
    ...stats,
    passAllRate: (stats.passAll / stats.total).toFixed(4),
    highAnyRate: (stats.highAny / stats.total).toFixed(4),
    subjects: Object.entries(stats.subjects).reduce((acc, [subject, data]) => ({
      ...acc,
      [subject]: {
        passRate: (data.pass / stats.total).toFixed(4),
        highRate: (data.high / stats.total).toFixed(4)
      }
    }), {})
  });

  // 生成最终结构化数据
  return {
    byClass: Object.fromEntries(
      Array.from(classStats).map(([classKey, stats]) => [
        classKey,
        { ...calculateRates(stats), total: stats.total }
      ])
    ),
    global: {
      ...calculateRates(globalStats),
      total: globalStats.total,
      subjects: Object.entries(globalStats.subjects).reduce((acc, [subject, data]) => ({
        ...acc,
        [subject]: {
          pass: data.pass,
          passRate: (data.pass / globalStats.total).toFixed(4),
          high: data.high,
          highRate: (data.high / globalStats.total).toFixed(4)
        }
      }), {})
    }
  };
}

// 使用示例
const result = analyzeResults(students, subjectConfig);
console.log(result);
数据分组
// 筛选+转换结合
const users = [
    {id: 1, name: 'Alice', age: 25},
    {id: 2, name: 'Bob', age: 30},
    {id: 3, name: 'Charlie', age: 25}
];

// 按年龄分组:相当于array_group_by()
const data = users.reduce((groups, user) => {
    const key = user.age;
    groups[key] = groups[key] || [];
    groups[key].push(user.name);
    return groups;
}, {});
console.log(data);
// 输出: {25: [Alice, Charlie], 30: [Bob]}

本文档综合了JavaScript的函数式编程、对象操作和类封装等最新实践,建议结合代码示例动手实验以加深理解。如需完整代码库参考,可查阅中的实战案例。