一、JavaScript 基础(重中之重)
1. 语言特性
数据类型:
基本类型(
null/undefined区别)、引用类型、类型转换(隐式转换规则)。一、基本数据类型(7 种) Undefined 表示未定义的变量(仅声明未赋值) 示例:let a; console.log(a); // undefined Null 表示空值或对象占位符 示例:let b = null; Boolean 逻辑值(true/false) 示例:let isValid = true; Number 整数或浮点数(如 42、3.14) 特殊值:NaN(非数字)、Infinity(无穷大) String 文本数据(如 "Hello") 支持模板字符串:`Count: ${count}` Symbol(ES6 新增) 唯一且不可变的值,用于对象属性键 示例:const key = Symbol('unique_id'); BigInt(ES2020 新增) 处理超大整数(超过 Number 安全范围) 示例:const bigNum = 9007199254740991n; 二、引用数据类型(1 种) Object 复杂数据结构,包含: 普通对象 {}(如 { name: 'Alice' }) 数组 [](如 [1, 2, 3]) 函数 function(){} 日期 Date、正则 RegExp 等内置对象原型与原型链(
prototype、__proto__):prototype、__proto__、继承实现(构造函数继承、原型链继承、组合继承等)。每个JavaScript函数都有一个prototype属性(箭头函数除外),该属性指向一个对象,称为原型对象。 当函数作为构造函数使用时(使用new调用),通过该构造函数创建的对象会继承其原型对象的属性和方法。 function Person(name) { this.name = name; } // 在原型上添加方法 Person.prototype.greet = function() { return `Hello, I'm ${this.name}`; }; const alice = new Person('Alice'); console.log(alice.greet()); // "Hello, I'm Alice"原型链(Prototype Chain) 当访问对象的属性时,JavaScript会: 在对象自身属性中查找 如果没找到,则沿着__proto__属性到其原型对象中查找 如果还没找到,则继续沿着原型的原型查找 直到找到属性或到达原型链顶端(Object.prototype.__proto__ === null) console.log(alice.toString()); // 来自Object.prototype原型链是JavaScript实现继承的基础 function Employee(name, title) { Person.call(this, name); // 继承属性 this.title = title; } // 设置原型链继承 Employee.prototype = Object.create(Person.prototype); Employee.prototype.constructor = Employee; // 添加子类方法 Employee.prototype.work = function() { return `${this.name} is working as ${this.title}`; }; const bob = new Employee('Bob', 'Developer'); console.log(bob.greet()); // "Hello, I'm Bob" (继承自Person) console.log(bob.work()); // "Bob is working as Developer"原型上的属性和方法被所有实例共享,节省内存: function Car(model) { this.model = model; } // 所有Car实例共享wheelCount和drive方法 Car.prototype.wheelCount = 4; Car.prototype.drive = function() { return `${this.model} is driving`; }; const car1 = new Car('Tesla'); const car2 = new Car('Toyota'); console.log(car1.wheelCount); // 4 console.log(car2.wheelCount); // 4作用域与闭包:
- 词法作用域、
var/let/const区别、闭包的应用场景(如函数防抖 / 节流)。JavaScript采用词法作用域(静态作用域),即变量的作用域在代码编写时就已经确定,而非运行时确定。 主要特点包括: 1.作用域层级: 全局作用域(Global Scope) 函数作用域(Function Scope) 块级作用域(Block Scope,ES6新增) 2.作用域链查找规则: 从当前作用域开始查找变量 如果找不到,向上一级作用域继续查找 直到全局作用域,若仍未找到则报错 let globalVar = 'global'; function outer() { let outerVar = 'outer'; function inner() { let innerVar = 'inner'; console.log(globalVar); // 可以访问所有外层变量 } inner(); }
特性 var let const 作用域 函数作用域或全局作用域 块级作用域 块级作用域 变量提升 会提升(值为undefined) 存在暂时性死区(TDZ) 存在暂时性死区(TDZ) 重复声明 允许 不允许 不允许 值可变性 可变 可变 不可变(引用类型内容可变) 全局属性 会成为window属性 不会成为window属性 不会成为window属性
闭包是指函数与其词法环境的组合,即使外部函数已执行完毕,内部函数仍能访问外部函数的变量 function createCounter() { let count = 0; // 闭包保护的变量 return { increment: () => ++count, getCount: () => count }; } const counter = createCounter(); counter.increment(); // count = 1通过闭包实现类似私有变量的效果 function createPrivateStore() { let data = {}; return { set(key, value) { data[key] = value; }, get(key) { return data[key]; } }; }函数防抖(Debounce) 限制函数在短时间内频繁触发 function debounce(fn, delay) { let timer = null; return function(...args) { clearTimeout(timer); timer = setTimeout(() => fn.apply(this, args), delay); }; } window.addEventListener('resize', debounce(() => { console.log('窗口大小调整结束'); }, 300));函数节流(Throttle) 保证函数在一定时间内只执行一次 function throttle(fn, interval) { let lastTime = 0; return function(...args) { const now = Date.now(); if (now - lastTime >= interval) { fn.apply(this, args); lastTime = now; } }; } window.addEventListener('scroll', throttle(() => { console.log('滚动事件处理'); }, 200));异步编程:
回调函数(Callback Hell 问题)。
回调函数是JavaScript异步编程的基础形式,通过将函数作为参数传递来实现异步操作完成后的处理。 function fetchData(callback) { setTimeout(() => { callback('Data received'); }, 1000); } fetchData((data) => { console.log(data); // 1秒后输出"Data received" });Callback Hell(回调地狱) 当多个异步操作需要顺序执行时,嵌套回调会导致代码难以维护 getUser(userId, (user) => { getOrders(user.id, (orders) => { getOrderDetails(orders[0].id, (details) => { getProductInfo(details.productId, (product) => { console.log(product); // 更多嵌套... }); }); }); });
Promise(状态机、then/catch/finally、链式调用)。1. Promise核心概念 Promise是ES6引入的异步编程解决方案,代表一个异步操作的最终完成或失败。 三种状态: pending:初始状态 fulfilled:操作成功完成 rejected:操作失败 const promise = new Promise((resolve, reject) => { setTimeout(() => { Math.random() > 0.5 ? resolve('Success!') : reject(new Error('Failed')); }, 1000); }); promise .then((result) => console.log(result)) .catch((error) => console.error(error)) .finally(() => console.log('Done'));Promise的核心优势是链式调用,解决回调地狱问题 function getUser(userId) { return new Promise((resolve) => resolve({ id: userId })); } function getOrders(userId) { return new Promise((resolve) => resolve([{ id: 'order1' }])); } getUser(123) .then(user => getOrders(user.id)) .then(orders => console.log(orders)) .catch(error => console.error(error));
Async/Await(与 Promise 的区别、错误处理)。Async/Await是建立在Promise之上的语法糖,使异步代码看起来像同步代码 async function fetchData() { try { const response = await fetch('api/data'); const data = await response.json(); console.log(data); } catch (error) { console.error('Error:', error); } }
特性 Promise Async/Await 语法结构 链式调用 同步写法 错误处理 .catch()方法 try/catch块 返回值 必须返回Promise 自动包装为Promise 可读性 中等 高 事件循环(Event Loop):
- Node.js 与浏览器 Event Loop 的差异
1. 浏览器Event Loop 浏览器中的事件循环处理顺序: 执行同步代码(调用栈) 执行当前所有微任务(Microtasks) Promise回调 MutationObserver queueMicrotask 渲染(如有需要) 执行一个宏任务(Macrotask) setTimeout/setInterval I/O操作 UI渲染 事件回调 重复循环 2. Node.js Event Loop Node.js的事件循环分为多个阶段: ┌───────────────────────┐ ┌─>│ timers │ (setTimeout/setInterval) │ └──────────┬────────────┘ │ ┌──────────┴────────────┐ │ │ pending callbacks │ (I/O回调) │ └──────────┬────────────┘ │ ┌──────────┴────────────┐ │ │ idle, prepare │ (内部使用) │ └──────────┬────────────┘ │ ┌──────────┴────────────┐ │ │ poll │ (检索新I/O事件) │ └──────────┬────────────┘ │ ┌──────────┴────────────┐ │ │ check │ (setImmediate) │ └──────────┬────────────┘ │ ┌──────────┴────────────┐ └──┤ close callbacks │ (关闭事件回调) └───────────────────────┘微任务(Microtask)与宏任务(Macrotask)的执行顺序。
特性 浏览器 Node.js 微任务执行时机 每个宏任务之后 每个阶段结束后 setImmediate 不支持 支持 process.nextTick 不支持 支持(优先级高于微任务) 渲染时机 在微任务之后 不适用 ES6+ 新特性:
模块化(
import/export与 CommonJS 的区别)。
特性 CommonJS (require/module.exports) ES Modules (import/export) 加载方式 运行时同步加载 编译时静态分析,异步加载 导出类型 动态导出(可条件导出) 静态导出(必须顶层导出) 值引用 导出值的拷贝 导出值的实时绑定(live binding) 循环引用处理 支持但可能部分未初始化 支持且保持引用关系 文件扩展名 .js/.cjs .mjs 或 package.json 中 type: "module" 顶级this 指向当前模块 undefined Node.js支持 原生支持 需要显式启用或在package.json配置 CommonJS示例: // math.js module.exports = { add: (a, b) => a + b }; // app.js const math = require('./math'); console.log(math.add(2, 3)); ES Modules示例: // math.mjs export const add = (a, b) => a + b; // app.mjs import { add } from './math.mjs'; console.log(add(2, 3));箭头函数(
this绑定、不能用作构造函数)。词法this绑定: function Person() { this.age = 0; // 传统函数 setInterval(function growUp() { this.age++; // 错误!这里的this指向全局或undefined }, 1000); // 箭头函数 setInterval(() => { this.age++; // 正确!继承Person的this }, 1000); }不能作为构造函数: const Foo = () => {}; new Foo(); // TypeError: Foo is not a constructor 没有prototype属性: console.log((() => {}).prototype); // undefined 不能使用arguments对象: const fn = () => console.log(arguments); fn(1, 2); // ReferenceError: arguments is not defined 简写语法: const double = x => x * 2; const sum = (a, b) => a + b;
Set/MapSet:值唯一的集合 const set = new Set([1, 2, 3, 3]); set.add(4).add(2); // 2不会被重复添加 console.log(set.has(3)); // true set.forEach(v => console.log(v)); Map:键值对集合(键可以是任意类型) const map = new Map(); map.set('name', 'Alice'); map.set({ id: 1 }, 'Complex Key'); console.log(map.get('name')); // 'Alice' for (let [key, value] of map) { console.log(key, value); }解构赋值
数组解构: const [first, , third] = [1, 2, 3]; console.log(first, third); // 1, 3 对象解构: const { name, age: userAge = 18 } = { name: 'Bob' }; console.log(name, userAge); // 'Bob', 18 函数参数解构: function greet({ name, age }) { return `Hello ${name}, you're ${age} years old`; } greet({ name: 'Alice', age: 25 });
SymbolSymbol 唯一标识符,常用于: 创建对象唯一属性键 实现元编程 const id = Symbol('id'); const user = { [id]: 123, name: 'Alice' }; console.log(user[id]); // 123 console.log(Object.keys(user)); // ['name'] (Symbol属性不可枚举)
Proxy/ReflectProxy:对象操作拦截器 const target = {}; const handler = { get(obj, prop) { return prop in obj ? obj[prop] : 37; } }; const p = new Proxy(target, handler); p.a = 1; console.log(p.a, p.b); // 1, 37Reflect:对象操作工具集 const obj = { x: 1, y: 2 }; console.log(Reflect.has(obj, 'x')); // true Reflect.set(obj, 'z', 3); console.log(obj.z); // 3
关键总结
模块化选择:
- 新项目推荐使用ES Modules
- 旧项目逐步迁移
- 注意文件扩展名和package.json配置
箭头函数适用场景:
- 需要词法this绑定的回调函数
- 简短的单行函数
- 避免在需要动态this的场景使用
现代数据结构优势:
- Set用于值唯一性处理
- Map优于普通对象当键需要非字符串时
- Symbol提供安全的属性键
元编程能力:
- Proxy实现高级对象拦截
- Reflect提供可靠的基础操作
- 两者结合可实现强大的元编程模式

9463

被折叠的 条评论
为什么被折叠?



