Portfolio
← 返回博客列表
JavaScript复习总结

2026-08-03 · 阅读 7

JavaScript复习总结

JS

JavaScript核心知识点总结

第一天基础夯实复习内容,涵盖原型链、闭包、作用域、异步编程、ES6+新特性

📚 目录

  1. 原型链
  2. 闭包
  3. 作用域
  4. 异步编程
  5. ES6+新特性

1. 原型链

核心概念

原型链是JavaScript实现继承的机制。每个对象都有一个__proto__属性,指向其构造函数的prototype

关键理解

  • 每个函数都有一个prototype属性(原型对象)
  • 每个对象都有一个__proto__属性(指向构造函数的prototype)
  • 当访问对象属性时,会沿着原型链向上查找
  • 原型链的终点是null

标准模板

// 创建父类
function Animal(name) {
  this.name = name;
}

Animal.prototype.eat = function() {
  console.log(this.name + '在吃东西');
};

// 创建子类继承父类(5步固定写法)
function Dog(name, breed) {
  // 步骤1:继承父类属性
  Animal.call(this, name);
  // 步骤2:子类自己的属性
  this.breed = breed;
}

// 步骤3:继承父类方法
Dog.prototype = Object.create(Animal.prototype);
// 步骤4:修正constructor指向
Dog.prototype.constructor = Dog;
// 步骤5:添加子类自己的方法
Dog.prototype.bark = function() {
  console.log(this.name + '汪汪叫');
};

// 创建实例
const dog = new Dog('旺财', '金毛');
dog.eat();   // 继承的方法
dog.bark();  // 子类自己的方法

原型链图解

dog实例
  │
  ├── name: '旺财'
  ├── breed: '金毛'
  │
  └── __proto__ → Dog.prototype
                    │
                    ├── bark()
                    ├── constructor → Dog
                    │
                    └── __proto__ → Animal.prototype
                                      │
                                      ├── eat()
                                      │
                                      └── __proto__ → Object.prototype
                                                        │
                                                        ├── toString()
                                                        │
                                                        └── __proto__ → null

2. 闭包

核心概念

闭包是指有权访问另一个函数作用域中变量的函数,即使外部函数已经执行结束。

三大应用场景

场景1:数据私有化(最常用)

function createCounter() {
  let count = 0;  // 私有变量

  return {
    increment() {
      count++;
      return count;
    },
    decrement() {
      count--;
      return count;
    },
    getCount() {
      return count;
    }
  };
}

const counter = createCounter();
console.log(counter.increment());  // 1
console.log(counter.increment());  // 2

场景2:函数工厂

function createMultiplier(倍数) {
  return function(数值) {
    return 数值 * 倍数;
  };
}

const double = createMultiplier(2);
const triple = createMultiplier(3);

console.log(double(5));   // 10
console.log(triple(5));   // 15

场景3:记忆化/缓存

function memoize(原函数) {
  const cache = {};

  return function(...args) {
    const key = args.join(',');

    if (cache[key] !== undefined) {
      console.log('从缓存返回');
      return cache[key];
    }

    const result = 原函数(...args);
    cache[key] = result;
    console.log('计算并缓存');
    return result;
  };
}

常见陷阱:循环中的闭包

// ❌ 错误示例
for (var i = 0; i < 3; i++) {
  setTimeout(function() {
    console.log(i);  // 输出:3, 3, 3
  }, 100);
}

// ✅ 解决方案1:使用let
for (let i = 0; i < 3; i++) {
  setTimeout(function() {
    console.log(i);  // 输出:0, 1, 2
  }, 100);
}

// ✅ 解决方案2:使用IIFE
for (var i = 0; i < 3; i++) {
  (function(j) {
    setTimeout(function() {
      console.log(j);  // 输出:0, 1, 2
    }, 100);
  })(i);
}

3. 作用域

三种作用域

  • 全局作用域:整个程序可见
  • 函数作用域:函数内部可见
  • 块级作用域let/const{} 内可见

作用域链

const globalVar = '全局';

function outerFunction() {
  const outerVar = '外部函数';

  function innerFunction() {
    const innerVar = '内部函数';

    console.log(innerVar);   // ✅ 当前作用域
    console.log(outerVar);   // ✅ 外部函数作用域
    console.log(globalVar);  // ✅ 全局作用域
  }

  innerFunction();
}

var vs let vs const

特性varletconst
作用域函数作用域块级作用域块级作用域
变量提升✅ 是❌ 否❌ 否
重复声明✅ 允许❌ 不允许❌ 不允许
重新赋值✅ 允许✅ 允许❌ 不允许
初始化可选可选必须初始化

最佳实践

  • 优先使用 const,其次 let,尽量避免 var
  • 在需要的地方声明变量,避免变量提升带来的困惑
  • 使用IIFE或块级作用域封装代码,避免污染全局

4. 异步编程

三种异步方式对比

方式1:回调函数(传统方式)

function fetchData(callback) {
  setTimeout(() => {
    callback(null, { id: 1, name: '张三' });
  }, 1000);
}

fetchData((error, data) => {
  if (error) {
    console.error(error);
    return;
  }
  console.log(data);
});

方式2:Promise(现代方式)

function fetchData() {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve({ id: 1, name: '张三' });
    }, 1000);
  });
}

fetchData()
  .then(data => console.log(data))
  .catch(error => console.error(error))
  .finally(() => console.log('清理工作'));

方式3:async/await(最优雅)

async function getData() {
  try {
    const response = await fetch('/api/data');
    const data = await response.json();
    console.log(data);
  } catch (error) {
    console.error(error);
  }
}

事件循环机制(重要!)

执行顺序:

同步代码 → 所有微任务 → 一个宏任务 → 所有微任务 → 循环...

示例:

console.log('1');                          // 同步
setTimeout(() => console.log('2'), 0);     // 宏任务
Promise.resolve().then(() => console.log('3')); // 微任务
console.log('4');                          // 同步

// 输出顺序:1, 4, 3, 2

原因:

  1. 同步代码先执行(1, 4)
  2. 微任务队列优先于宏任务队列(3)
  3. 宏任务最后执行(2)

Promise.all vs Promise.race

// Promise.all:等所有完成
const [users, posts, comments] = await Promise.all([
  fetch('/api/users').then(r => r.json()),
  fetch('/api/posts').then(r => r.json()),
  fetch('/api/comments').then(r => r.json())
]);

// Promise.race:返回最先完成的
const result = await Promise.race([
  fetch('/api/fast'),
  fetch('/api/slow')
]);

实战案例:倒计时

function delay(ms) {
  return new Promise(resolve => setTimeout(resolve, ms));
}

async function countdown(seconds) {
  for (let i = seconds; i > 0; i--) {
    console.log(i);
    await delay(1000);
  }
  console.log('发射!');
}

countdown(10);

5. ES6+新特性

解构赋值

// 对象解构
const { name, age, city: cityName } = person;

// 数组解构
const [first, second, ...rest] = numbers;

// 函数参数解构
function greet({ name, age = 20 }) {
  console.log(`你好,我是${name},今年${age}岁`);
}

展开运算符

// 数组展开
const merged = [...arr1, ...arr2];

// 对象展开
const newObj = { ...obj1, ...obj2 };

// Rest参数
function sum(...args) {
  return args.reduce((total, num) => total + num, 0);
}

箭头函数

const add = (a, b) => a + b;
const square = x => x * x;

// 注意:箭头函数没有自己的this
const obj = {
  name: '对象',
  normalFunc() {
    console.log(this.name);  // ✅ '对象'
  },
  arrowFunc: () => {
    console.log(this.name);  // ❌ undefined
  }
};

模板字符串

const greeting = `你好,我是${name},今年${age}岁。`;

// 多行字符串
const html = `
  <div>
    <h1>${title}</h1>
  </div>
`;

类和继承

class Animal {
  constructor(name) {
    this.name = name;
  }

  speak() {
    console.log(`${this.name}发出声音`);
  }

  static info() {
    console.log('这是Animal类');
  }
}

class Dog extends Animal {
  constructor(name, breed) {
    super(name);
    this.breed = breed;
  }

  speak() {
    console.log(`${this.name}汪汪叫`);
  }
}

可选链操作符(?.)

const age = user?.profile?.age;  // 安全访问,不会报错
const result = obj.method?.();   // 安全调用方法

空值合并运算符(??)

// || 运算符:falsy值都会使用右侧
console.log(0 || '默认值');      // '默认值'
console.log('' || '默认值');     // '默认值'

// ?? 运算符:只有null和undefined才使用右侧
console.log(0 ?? '默认值');      // 0(保留)
console.log('' ?? '默认值');     // ''(保留)
console.log(null ?? '默认值');   // '默认值'

📝 学习建议

理解优先级

  1. 原型链:理解继承机制,掌握5步继承模板
  2. 闭包:理解三大应用场景,避免常见陷阱
  3. 作用域:理解作用域链,区分var/let/const
  4. 异步编程:掌握async/await,理解事件循环
  5. ES6+新特性:掌握常用语法,提升开发效率

练习建议

  • 先理解概念,再看代码示例
  • 动手敲代码,不要只看不练
  • 尝试修改示例代码,观察变化
  • 完成每个知识点的练习题

常见陷阱

  • 原型链忘记修正constructor
  • 循环中使用var导致闭包问题
  • 箭头函数误用导致this指向错误
  • 异步操作不理解事件循环机制

🎯 总结

JavaScript核心知识点可以归纳为:

  1. 原型链:实现继承的机制,掌握标准模板
  2. 闭包:数据私有化、函数工厂、缓存的利器
  3. 作用域:理解作用域链,合理使用var/let/const
  4. 异步编程:async/await最优雅,理解事件循环
  5. ES6+新特性:掌握解构、箭头函数、类等常用特性

掌握这些核心概念,就能在面试和实际开发中游刃有余!