Skip to content

章节2 — JavaScript 核心语法


一、章节概述

JavaScript 是 Web 前端的灵魂语言。本章从变量与类型出发,逐步覆盖运算符、流程控制、函数、数组对象,深入 ES6+ 新特性(解构、展开、模板字符串、Map/Set),并重点讲解 Promise 与 async/await 异步编程模型,为后续框架学习打下坚实基础。


二、学习目标

目标分类具体目标
知识目标理解 var/let/const 区别;掌握 JS 数据类型体系;理解同步与异步执行模型
技能目标能熟练使用 ES6+ 语法编写现代代码;能用 Promise / async/await 处理异步操作
素质目标培养严谨的类型意识与异步编程思维

三、核心知识点

3.1 变量声明与数据类型

3.1.1 var / let / const

声明方式作用域变量提升重复声明暂存死区可否修改
var函数作用域✅ 提升为 undefined✅ 允许
let块级作用域 {}✅ 提升但不初始化❌ 报错✅ 存在
const块级作用域 {}✅ 提升但不初始化❌ 报错✅ 存在❌ 基本类型不可变;对象属性可改
javascript
// var 的问题
console.log(a); // undefined(提升)
var a = 10;

// let / const 示例
let score = 95;
if (score >= 90) {
  let level = "优秀";
  console.log(level); // "优秀"
}
// console.log(level); // ❌ ReferenceError

const PI = 3.14159;
// PI = 3; // ❌ 报错

const user = { name: "Alice" };
user.name = "Bob"; // ✅ 允许,对象引用未变

最佳实践:默认使用 const,只在需要重新赋值时用 let永远不用 var

3.1.2 数据类型

JavaScript 有 7 种基本类型 + 1 种引用类型:

类型typeof 返回值示例
number"number"42, 3.14, NaN, Infinity
string"string""hello", 'world', `模板`
boolean"boolean"true, false
undefined"undefined"let x;
null"object"(语言 bug)let y = null;
symbol"symbol"Symbol("id")
bigint"bigint"9007199254740991n
object"object"{}, [], function
javascript
// 类型检测注意事项
typeof null       // "object"(历史遗留 bug)
typeof [1, 2, 3]  // "object"
Array.isArray([1, 2, 3]) // true ✅

// 常见类型转换
Number("42")      // 42
String(42)        // "42"
Boolean(0)        // false
Boolean("")       // false
Boolean("false")  // true ✅ 非空字符串为 true

3.2 运算符、流程控制与函数

3.2.1 常用运算符

javascript
// 严格相等(推荐)
1 === "1"   // false
1 == "1"    // true(隐式转换,不推荐)

// 可选链 ?.
const user = { profile: { name: "Alice" } };
console.log(user?.profile?.name);  // "Alice"
console.log(user?.address?.city);  // undefined(不报错)

// 空值合并 ??
const count = 0 ?? 10;  // 0(?? 只对 null/undefined 生效)
const count2 = 0 || 10; // 10(|| 对所有假值生效)

3.2.2 流程控制

javascript
// if / else if / else
const age = 20;
if (age < 18) {
  console.log("未成年");
} else if (age < 60) {
  console.log("成年");
} else {
  console.log("老年");
}

// switch
const day = 3;
let dayName;
switch (day) {
  case 1: dayName = "周一"; break;
  case 2: dayName = "周二"; break;
  case 3: dayName = "周三"; break;
  default: dayName = "其他";
}

// 循环
for (let i = 0; i < 5; i++) { /* 传统 for */ }
for (const item of arr) { /* 遍历数组 */ }
for (const key in obj) { /* 遍历对象键 */ }

3.2.3 函数定义方式

javascript
// 1. 函数声明(提升)
function add(a, b) {
  return a + b;
}

// 2. 函数表达式(不提升)
const subtract = function (a, b) {
  return a - b;
};

// 3. 箭头函数(推荐现代写法)
const multiply = (a, b) => a * b;

// 4. 默认参数
const greet = (name = "游客") => `你好,${name}!`;

// 5. 剩余参数
const sum = (...numbers) => numbers.reduce((acc, n) => acc + n, 0);

3.3 数组、对象与 ES6+ 新特性

3.3.1 数组核心方法

方法用途是否改变原数组
push(e) / pop()尾部增删
unshift(e) / shift()头部增删
slice(start, end)截取片段
splice(idx, del, ...items)任意位置增删改
forEach(fn)遍历
map(fn)映射为新数组
filter(fn)过滤
reduce(fn, init)归约
find(fn)查找第一个匹配元素
some(fn) / every(fn)判断部分/全部满足
javascript
const nums = [1, 2, 3, 4, 5];

// 链式调用
const result = nums
  .filter(n => n > 2)     // [3, 4, 5]
  .map(n => n * 10)       // [30, 40, 50]
  .reduce((acc, n) => acc + n, 0); // 120

3.3.2 ES6+ 新特性

解构赋值

javascript
// 数组解构
const [a, b, ...rest] = [1, 2, 3, 4];
console.log(a, b, rest); // 1 2 [3, 4]

// 对象解构
const person = { name: "Bob", age: 25, city: "北京" };
const { name, age, ...others } = person;
console.log(name, others); // "Bob" { city: "北京" }

// 嵌套解构 + 重命名
const data = { user: { id: 1, info: { email: "a@b.com" } } };
const { user: { info: { email: mail } } } = data;
console.log(mail); // "a@b.com"

展开运算符 ...

javascript
// 数组合并
const arr1 = [1, 2], arr2 = [3, 4];
const merged = [...arr1, ...arr2]; // [1, 2, 3, 4]

// 对象拷贝与合并
const base = { x: 1, y: 2 };
const copy = { ...base, z: 3 }; // { x: 1, y: 2, z: 3 }

// 函数参数展开
const max = Math.max(...[10, 20, 30]); // 30

模板字符串

javascript
const name = "Alice", age = 30;
const greeting = `你好,我是 ${name},今年 ${age} 岁。`;
// 支持多行
const html = `
  <div class="card">
    <h2>${name}</h2>
  </div>
`;

Map 与 Set

javascript
// Map — 键值对集合(键可以是任意类型)
const map = new Map();
map.set("name", "Alice");
map.set(42, "答案是");
console.log(map.get(42)); // "答案是"
console.log(map.size);    // 2

// Set — 唯一值集合
const set = new Set([1, 2, 2, 3, 3, 3]);
console.log([...set]);  // [1, 2, 3]

// 实用场景:数组去重
const unique = [...new Set([1, 2, 2, 3, 3, 4])]; // [1, 2, 3, 4]

3.4 Promise 异步编程与 async/await

3.4.1 回调与 Promise

javascript
// 传统回调(回调地狱)
setTimeout(() => {
  console.log("第1步");
  setTimeout(() => {
    console.log("第2步");
    setTimeout(() => {
      console.log("第3步");
    }, 1000);
  }, 1000);
}, 1000);

// Promise 链式调用
new Promise((resolve) => {
  setTimeout(() => { console.log("第1步"); resolve(); }, 1000);
})
.then(() => new Promise((resolve) => {
  setTimeout(() => { console.log("第2步"); resolve(); }, 1000);
}))
.then(() => new Promise((resolve) => {
  setTimeout(() => { console.log("第3步"); resolve(); }, 1000);
}));

3.4.2 Promise 静态方法

javascript
const p1 = fetch("/api/user").then(r => r.json());
const p2 = fetch("/api/posts").then(r => r.json());

// 全部完成
Promise.all([p1, p2]).then(([user, posts]) => {
  console.log("用户:", user, "文章:", posts);
});

// 任一完成
Promise.race([p1, p2]).then(first => console.log("先完成:", first));

// 全部完成(不关心失败)
Promise.allSettled([p1, p2]).then(results => {
  results.forEach(r => console.log(r.status, r.value || r.reason));
});

3.4.3 async / await(语法糖)

javascript
// async 函数返回一个 Promise
async function fetchUserData(userId) {
  try {
    const response = await fetch(`/api/users/${userId}`);
    if (!response.ok) throw new Error("请求失败");
    const data = await response.json();
    return data;
  } catch (error) {
    console.error("捕获错误:", error);
    throw error; // 让调用方继续处理
  }
}

// 使用
(async () => {
  const user = await fetchUserData(1);
  console.log(user);
})();

关键原则await 只能在 async 函数中使用;async 函数始终返回 Promise。

3.4.4 并行请求优化

javascript
// ❌ 顺序请求(慢)
async function sequential() {
  const a = await fetch("/api/a").then(r => r.json());
  const b = await fetch("/api/b").then(r => r.json()); // 等 a 完成
}

// ✅ 并行请求(快)
async function parallel() {
  const [a, b] = await Promise.all([
    fetch("/api/a").then(r => r.json()),
    fetch("/api/b").then(r => r.json()),
  ]);
}

3.5 箭头函数深入与展开运算符应用

3.5.1 箭头函数 vs 普通函数

特性普通函数箭头函数
this 指向动态,取决于调用方式词法绑定,继承外层 this
arguments❌ 无,用 ...args 替代
new 调用可作为构造函数❌ 不能
简洁度较长极简
javascript
const obj = {
  name: "Alice",
  sayLater: function () {
    // 普通函数中 this 指向 obj
    setTimeout(function () {
      console.log(this.name); // undefined(this 指向全局)
    }, 100);
  },
  sayLaterArrow: function () {
    // 箭头函数继承外层 this
    setTimeout(() => {
      console.log(this.name); // "Alice" ✅
    }, 100);
  },
};

3.5.2 综合应用场景

javascript
// 数组处理(现代写法)
const students = [
  { name: "张三", score: 85 },
  { name: "李四", score: 92 },
  { name: "王五", score: 78 },
];

// 1. 过滤出成绩 ≥ 80 的学生
const excellent = students
  .filter(({ score }) => score >= 80)
  .map(({ name, score }) => `${name}:${score}分`);

// 2. 计算平均分
const avg = students
  .reduce((sum, { score }) => sum + score, 0) / students.length;

// 3. 对象快速转换
const scoreMap = Object.fromEntries(
  students.map(({ name, score }) => [name, score])
);
// { "张三": 85, "李四": 92, "王五": 78 }

四、小结

知识点核心要点
变量声明默认 const,需要重赋值用 let,不用 var
数据类型7 基本 + 1 引用;注意 typeof null === "object"
流程控制可选链 ?. 与空值合并 ?? 是现代 JS 标配
数组方法map / filter / reduce 链式调用是核心范式
ES6+解构、展开、模板字符串、Map/Set 极大提升开发效率
异步编程async/await + Promise.all 是主流异步方案
箭头函数不绑定 this,适合回调;不能作为构造函数

五、练习

基础题

  1. 声明一个 const 数组 [1, 2, 3, 4, 5],用解构取出前两个值,并用展开运算符将其与 [6, 7, 8] 合并。
  2. 编写一个箭头函数 isPalindrome(str),用展开 + 数组方法判断字符串是否为回文(如 "racecar")。
  3. map + 模板字符串,将 [{name: "小明", age: 18}, {name: "小红", age: 20}] 转为 "小明18岁" / "小红20岁" 格式数组。

进阶题

  1. 使用 async/await + Promise.all 编写一个函数 fetchMultiple(urls),传入 URL 数组,并行请求所有资源,返回解析后的 JSON 数组。
  2. Set 实现数组去重,再用 Map 统计数组中每个元素出现的次数(如 [1, 2, 2, 3, 3, 3]{1: 1, 2: 2, 3: 3})。

挑战题

  1. 不使用 Promise.all,手写一个 myPromiseAll(promises) 函数,实现相同功能:所有 promise 成功则返回结果数组,任一失败则立即 reject。

Python 学习资料