1. JavaScript基础入门:从零开始掌握核心语法
JavaScript作为现代Web开发的三大基石之一,已经成为前端工程师必须精通的编程语言。对于初学者而言,掌握JavaScript的基础语法是迈向高级开发的第一步。让我们从最基础的变量声明开始,逐步构建完整的知识体系。
1.1 变量声明:var、let与const的区别
在ES6之前,JavaScript只有var一种变量声明方式,这导致了许多作用域相关的问题。ES6引入了let和const,为变量声明带来了更精确的控制:
// 传统var声明 - 函数作用域 var oldVariable = 'I am hoisted!'; // 现代let声明 - 块级作用域 let mutableVar = 'I can change'; mutableVar = 'new value'; // 常量const声明 - 不可重新赋值 const PI = 3.14159; // PI = 3.14; // 报错:Assignment to constant variable关键区别:
- var存在变量提升(hoisting),let/const不存在
- var是函数作用域,let/const是块级作用域
- const必须初始化且不能重新赋值,但对象属性可以修改
提示:现代开发中优先使用const,需要重新赋值时才用let,避免使用var
1.2 数据类型与类型转换
JavaScript是动态类型语言,但了解其数据类型对写出健壮代码至关重要:
// 原始类型 let str = "Hello"; // string let num = 42; // number let bigInt = 9007199254740991n; // bigint let bool = true; // boolean let nothing = null; // null let notDefined; // undefined let sym = Symbol("id"); // symbol // 对象类型 let obj = { name: "Object" }; let arr = [1, 2, 3]; let func = function() {};类型转换是常见操作:
// 显式转换 let strToNum = Number("123"); // 123 let numToStr = String(123); // "123" // 隐式转换 let implicit = "5" * 2; // 10 (number)2. 函数与作用域:构建可重用代码块
函数是JavaScript中最重要的概念之一,理解函数的工作方式对编写高质量代码至关重要。
2.1 函数定义与调用
JavaScript提供了多种定义函数的方式:
// 函数声明 (会提升) function add(a, b) { return a + b; } // 函数表达式 const multiply = function(a, b) { return a * b; }; // 箭头函数 (ES6+) const divide = (a, b) => a / b; // 立即执行函数(IIFE) (function() { console.log("立即执行"); })();2.2 作用域与闭包
JavaScript采用词法作用域(静态作用域),函数在定义时就确定了作用域链:
function outer() { let outerVar = '外部'; function inner() { let innerVar = '内部'; console.log(outerVar); // 可以访问外部变量 } // console.log(innerVar); // 报错:无法访问内部变量 return inner; } const closureFunc = outer(); closureFunc(); // 仍然可以访问outerVar闭包的应用场景:
- 模块模式(封装私有变量)
- 函数工厂
- 记忆化(缓存计算结果)
- 事件处理回调
3. 数组操作:高效处理数据集合
数组是JavaScript中最常用的数据结构之一,掌握其方法能极大提升开发效率。
3.1 基本数组方法
let fruits = ['Apple', 'Orange']; // 添加/删除元素 fruits.push('Banana'); // 末尾添加 fruits.pop(); // 末尾删除 fruits.unshift('Grape');// 开头添加 fruits.shift(); // 开头删除 // 切片与拼接 let citrus = fruits.slice(1, 3); // 不改变原数组 fruits.splice(1, 0, 'Lemon'); // 改变原数组 // 查找 let index = fruits.indexOf('Orange'); let exists = fruits.includes('Apple');3.2 高阶数组方法
ES6引入的迭代方法让数组处理更加函数式:
const numbers = [1, 2, 3, 4, 5]; // map - 转换数组 const doubled = numbers.map(n => n * 2); // filter - 筛选元素 const evens = numbers.filter(n => n % 2 === 0); // reduce - 累积计算 const sum = numbers.reduce((acc, n) => acc + n, 0); // every/some - 条件检测 const allPositive = numbers.every(n => n > 0); const hasEven = numbers.some(n => n % 2 === 0);经验:当需要同时使用filter和map时,考虑使用reduce一次完成,避免多次遍历数组
4. 对象与原型:深入JavaScript面向对象
JavaScript采用基于原型的面向对象模型,与传统基于类的语言有所不同。
4.1 对象创建与属性
// 对象字面量 const person = { name: 'Alice', age: 30, greet() { console.log(`Hello, I'm ${this.name}`); } }; // 属性访问 console.log(person.name); // 点表示法 console.log(person['age']); // 方括号表示法 // 属性描述符 Object.defineProperty(person, 'job', { value: 'Developer', writable: false, // 不可修改 enumerable: true // 可枚举 });4.2 原型与继承
每个JavaScript对象都有一个原型链,用于实现继承:
// 构造函数 function Animal(name) { this.name = name; } // 原型方法 Animal.prototype.speak = function() { console.log(`${this.name} makes a noise.`); }; // 继承 function Dog(name) { Animal.call(this, name); } Dog.prototype = Object.create(Animal.prototype); Dog.prototype.constructor = Dog; Dog.prototype.speak = function() { console.log(`${this.name} barks.`); }; const d = new Dog('Rex'); d.speak(); // "Rex barks."现代JavaScript(ES6+)提供了class语法糖,使原型继承更易理解:
class Animal { constructor(name) { this.name = name; } speak() { console.log(`${this.name} makes a noise.`); } } class Dog extends Animal { speak() { console.log(`${this.name} barks.`); } }5. 异步编程:处理非阻塞操作
JavaScript是单线程语言,异步编程是其核心特性之一。
5.1 回调与Promise
传统回调方式容易导致"回调地狱":
function fetchData(callback) { setTimeout(() => { callback('Data received'); }, 1000); } fetchData(data => { console.log(data); fetchMoreData(moreData => { console.log(moreData); // 更多嵌套... }); });Promise提供了更优雅的解决方案:
function fetchData() { return new Promise((resolve, reject) => { setTimeout(() => { resolve('Data received'); // 或 reject('Error occurred'); }, 1000); }); } fetchData() .then(data => { console.log(data); return fetchMoreData(); }) .then(moreData => { console.log(moreData); }) .catch(error => { console.error(error); });5.2 async/await语法
ES2017引入的async/await让异步代码看起来像同步代码:
async function getData() { try { const data = await fetchData(); const moreData = await fetchMoreData(); console.log(data, moreData); } catch (error) { console.error(error); } } // 立即执行async函数 (async () => { await getData(); })();注意:await只能在async函数中使用,顶层await在模块中可用
6. DOM操作:动态交互网页
文档对象模型(DOM)是JavaScript与网页交互的接口。
6.1 元素选择与操作
// 选择元素 const header = document.getElementById('header'); const buttons = document.querySelectorAll('.btn'); const firstPara = document.querySelector('p'); // 修改内容 header.textContent = 'New Title'; firstPara.innerHTML = '<strong>Bold</strong> text'; // 样式操作 header.style.color = 'blue'; header.classList.add('highlight'); // 创建新元素 const newDiv = document.createElement('div'); newDiv.className = 'alert'; newDiv.textContent = 'Hello!'; document.body.appendChild(newDiv);6.2 事件处理
JavaScript通过事件监听实现交互:
// 添加事件监听 const btn = document.querySelector('#myButton'); btn.addEventListener('click', function(event) { console.log('Button clicked!', event); }); // 事件委托 document.querySelector('#list').addEventListener('click', function(e) { if(e.target.tagName === 'LI') { console.log('List item clicked:', e.target.textContent); } }); // 自定义事件 const event = new CustomEvent('build', { detail: { time: Date.now() } }); document.dispatchEvent(event);7. 现代JavaScript特性(ES6+)
ECMAScript 6及后续版本为JavaScript带来了许多强大特性。
7.1 解构赋值
// 数组解构 const [first, second] = [1, 2, 3]; console.log(first); // 1 // 对象解构 const { name, age } = { name: 'Alice', age: 30 }; console.log(name); // 'Alice' // 函数参数解构 function greet({ name, age }) { console.log(`Hello ${name}, you are ${age}`); } greet({ name: 'Bob', age: 25 });7.2 模块系统
现代JavaScript支持模块化开发:
// math.js export const PI = 3.14159; export function square(x) { return x * x; } // app.js import { PI, square } from './math.js'; console.log(square(PI));7.3 可选链与空值合并
const user = { profile: { name: 'Alice', address: { city: 'New York' } } }; // 传统方式 const city = user && user.profile && user.profile.address && user.profile.address.city; // 可选链 const city = user?.profile?.address?.city; // 空值合并 const defaultCity = city ?? 'Unknown';8. 实用技巧与最佳实践
8.1 代码组织与可读性
- 使用一致的命名约定(camelCase变量,PascalCase类,UPPER_CASE常量)
- 保持函数单一职责(一个函数只做一件事)
- 合理使用注释(解释为什么,而不是做什么)
- 采用模块化组织代码
8.2 性能优化
// 避免不必要的DOM操作 const fragment = document.createDocumentFragment(); for(let i = 0; i < 100; i++) { const div = document.createElement('div'); fragment.appendChild(div); } document.body.appendChild(fragment); // 事件节流与防抖 function debounce(func, delay) { let timeout; return function() { clearTimeout(timeout); timeout = setTimeout(() => func.apply(this, arguments), delay); }; } window.addEventListener('resize', debounce(() => { console.log('Resize handler'); }, 200));8.3 调试技巧
// 条件调试 if (DEBUG_MODE) { console.log('Debug info'); } // 性能测量 console.time('loop'); for(let i = 0; i < 1000000; i++) {} console.timeEnd('loop'); // 错误处理 try { riskyOperation(); } catch (error) { console.error('Operation failed:', error); // 优雅降级 fallbackOperation(); } finally { cleanup(); }9. 实战项目:构建一个待办事项应用
让我们综合运用所学知识,构建一个完整的待办事项应用。
9.1 HTML结构
<!DOCTYPE html> <html> <head> <title>Todo App</title> <style> .completed { text-decoration: line-through; } </style> </head> <body> <h1>Todo List</h1> <form id="todo-form"> <input type="text" id="todo-input" required> <button type="submit">Add</button> </form> <ul id="todo-list"></ul> <script src="app.js"></script> </body> </html>9.2 JavaScript实现
// app.js class TodoApp { constructor() { this.todos = JSON.parse(localStorage.getItem('todos')) || []; this.form = document.getElementById('todo-form'); this.input = document.getElementById('todo-input'); this.list = document.getElementById('todo-list'); this.form.addEventListener('submit', this.addTodo.bind(this)); this.render(); } addTodo(e) { e.preventDefault(); const text = this.input.value.trim(); if (text) { this.todos.push({ text, completed: false }); this.save(); this.input.value = ''; this.render(); } } toggleTodo(index) { this.todos[index].completed = !this.todos[index].completed; this.save(); this.render(); } deleteTodo(index, e) { e.stopPropagation(); this.todos.splice(index, 1); this.save(); this.render(); } save() { localStorage.setItem('todos', JSON.stringify(this.todos)); } render() { this.list.innerHTML = ''; this.todos.forEach((todo, index) => { const li = document.createElement('li'); li.textContent = todo.text; if (todo.completed) { li.classList.add('completed'); } const deleteBtn = document.createElement('button'); deleteBtn.textContent = 'Delete'; deleteBtn.addEventListener('click', (e) => this.deleteTodo(index, e)); li.appendChild(deleteBtn); li.addEventListener('click', () => this.toggleTodo(index)); this.list.appendChild(li); }); } } new TodoApp();这个简单的应用涵盖了:
- 类与方法的组织
- DOM操作与事件处理
- 本地存储(localStorage)
- 数组操作
- 条件渲染
10. JavaScript生态系统与进阶学习
10.1 流行框架与库
- React:Facebook开发的UI库,基于组件化思想
- Vue:渐进式框架,易于集成和学习
- Angular:Google开发的全功能框架
- Node.js:JavaScript运行时,用于服务器端开发
- Express:Node.js的Web框架
- TypeScript:JavaScript的超集,添加静态类型
10.2 构建工具与包管理
- npm/yarn:JavaScript包管理器
- Webpack:模块打包工具
- Babel:JavaScript编译器(将ES6+转换为兼容代码)
- ESLint:代码质量检查工具
- Prettier:代码格式化工具
10.3 学习资源推荐
- MDN Web Docs:最权威的JavaScript文档
- Eloquent JavaScript:优秀的免费在线书籍
- JavaScript.info:详细的现代JavaScript教程
- Frontend Masters:高质量付费课程平台
- LeetCode/CodeWars:编程练习平台
11. 常见面试问题与解答
11.1 基础概念
问题:解释事件循环(Event Loop)的工作原理
JavaScript是单线程的,事件循环是其实现非阻塞I/O的机制。调用栈执行同步代码,异步操作(如setTimeout、Promise等)会被放入任务队列。当调用栈为空时,事件循环会从任务队列中取出任务执行。任务队列又分为宏任务(script整体代码、setTimeout等)和微任务(Promise.then、process.nextTick等),微任务优先级高于宏任务。
11.2 代码输出题
问题:以下代码输出什么?为什么?
console.log('1'); setTimeout(() => console.log('2'), 0); Promise.resolve().then(() => console.log('3')); console.log('4');输出顺序:1, 4, 3, 2
解释:
- 同步代码先执行(1和4)
- Promise.then是微任务,优先于宏任务执行(3)
- setTimeout是宏任务,最后执行(2)
11.3 算法实现
问题:实现数组去重
// 方法1:使用Set function unique(arr) { return [...new Set(arr)]; } // 方法2:使用filter function unique(arr) { return arr.filter((item, index) => arr.indexOf(item) === index); } // 方法3:使用reduce function unique(arr) { return arr.reduce((acc, cur) => acc.includes(cur) ? acc : [...acc, cur], []); }12. 安全性与性能优化
12.1 常见安全风险
- XSS(跨站脚本攻击):永远不要信任用户输入,对输出进行转义
- CSRF(跨站请求伪造):使用CSRF令牌,设置SameSite cookie属性
- JSON劫持:避免敏感数据的JSONP接口,使用JSON.parse而非eval
- 原型污染:避免使用不安全的对象合并方法
12.2 性能优化技巧
- 减少重绘与回流:批量DOM操作,使用transform代替top/left
- 代码分割:按需加载代码(Webpack的splitChunks)
- 图片优化:使用WebP格式,懒加载非首屏图片
- 缓存策略:合理设置Cache-Control,使用Service Worker
- Web Workers:将耗时任务放到后台线程
13. 调试与错误处理
13.1 Chrome开发者工具技巧
- 断点调试:在Sources面板设置断点,查看调用栈
- 性能分析:使用Performance面板记录和分析运行时性能
- 内存分析:使用Memory面板检测内存泄漏
- 网络分析:Network面板查看请求瀑布图,优化加载顺序
13.2 错误监控
// 全局错误处理 window.addEventListener('error', function(event) { // 发送错误到服务器 sendErrorToServer({ message: event.message, filename: event.filename, lineno: event.lineno, colno: event.colno }); }); // Promise未捕获错误 window.addEventListener('unhandledrejection', function(event) { console.error('Unhandled rejection:', event.reason); });14. 测试与质量保证
14.1 单元测试
使用Jest测试框架示例:
// math.js export function sum(a, b) { return a + b; } // math.test.js import { sum } from './math'; test('adds 1 + 2 to equal 3', () => { expect(sum(1, 2)).toBe(3); }); test('adds 0 + 0 to equal 0', () => { expect(sum(0, 0)).toBe(0); });14.2 端到端测试
使用Cypress示例:
describe('Todo App', () => { it('adds a new todo', () => { cy.visit('/'); cy.get('#todo-input').type('Buy milk'); cy.get('button[type="submit"]').click(); cy.contains('li', 'Buy milk').should('exist'); }); });15. 未来趋势与WebAssembly
15.1 JavaScript新特性
- 顶层await:在模块中直接使用await
- 私有类字段:使用#前缀定义私有属性
- 装饰器:@语法用于类和类成员
- Record & Tuple:不可变数据结构
15.2 WebAssembly
WebAssembly(Wasm)允许在浏览器中运行高性能的编译代码,与JavaScript互补:
// 加载并运行Wasm模块 WebAssembly.instantiateStreaming(fetch('module.wasm')) .then(obj => { const result = obj.instance.exports.add(1, 2); console.log(result); // 3 });使用场景:
- 性能敏感应用(游戏、图像处理)
- 移植现有C++/Rust代码到Web
- 加密计算等密集型任务
16. 个人项目建议与学习路径
16.1 练手项目创意
- 天气应用:使用公开API获取并显示天气数据
- Markdown编辑器:实时预览Markdown转换
- 聊天应用:使用WebSocket实现实时通信
- 游戏:使用Canvas或Phaser.js开发简单游戏
- 个人博客:使用静态站点生成器(如Hexo)
16.2 学习路径建议
基础阶段(1-2个月):
- 掌握JavaScript核心语法
- 理解DOM操作和事件处理
- 学习ES6+新特性
中级阶段(2-3个月):
- 深入理解异步编程
- 学习模块化和构建工具
- 选择一个前端框架(React/Vue)
高级阶段(持续):
- 性能优化与安全
- 测试驱动开发
- 数据结构与算法
- 服务端开发(Node.js)
17. 社区参与与持续学习
17.1 开源贡献
- 从文档改进开始参与开源项目
- 解决标记为"good first issue"的问题
- 创建自己的开源项目
17.2 技术社区
- Stack Overflow:提问和回答问题
- GitHub:托管代码,参与协作
- Dev.to:技术博客平台
- Twitter:关注JavaScript专家
- 本地Meetup:参加线下技术活动
17.3 持续学习策略
- 每周阅读技术文章/博客
- 每月完成一个小项目
- 每季度学习一个新工具或框架
- 参加在线课程或认证
- 定期回顾和重构旧代码
18. 职业发展与JavaScript工程师
18.1 职业路径
- 前端工程师:专注于浏览器端开发
- 全栈工程师:同时掌握前端和后端(Node.js)
- JavaScript架构师:设计复杂应用架构
- 技术主管/CTO:领导技术团队和决策
18.2 薪资与市场需求
根据2023年数据:
- 初级JavaScript开发:$60,000 - $90,000
- 中级开发:$90,000 - $120,000
- 高级/全栈开发:$120,000 - $160,000
- 技术主管/架构师:$150,000+
18.3 简历与面试准备
- 展示个人项目和GitHub
- 准备算法题(排序、搜索、数据结构)
- 理解浏览器工作原理
- 熟悉至少一个主流框架的底层原理
- 准备项目经验的故事(挑战、解决方案、结果)
19. 常见陷阱与如何避免
19.1 初学者常见错误
滥用全局变量:污染全局命名空间
- 解决:使用模块模式,const/let
忽略异步特性:预期同步执行的异步代码
- 解决:理解Promise,合理使用async/await
过度操作DOM:导致性能问题
- 解决:批量更新,使用文档片段
不处理错误:导致应用崩溃
- 解决:添加try/catch,全局错误处理
19.2 代码质量陷阱
过长的函数:难以维护和测试
- 解决:遵循单一职责原则,拆分为小函数
深层嵌套:回调地狱或条件嵌套
- 解决:使用Promise/async,提前返回
魔法数字/字符串:难以理解的硬编码值
- 解决:定义为有意义的常量
缺乏注释:特别是复杂业务逻辑
- 解决:添加解释"为什么"的注释
20. 工具链与开发环境
20.1 编辑器与IDE
- VS Code:轻量级,丰富的扩展
- 推荐插件:ESLint, Prettier, Debugger for Chrome
- WebStorm:功能全面的JavaScript IDE
- Vim/Emacs:适合高级用户
20.2 浏览器工具
- Chrome DevTools:元素检查,性能分析
- Firefox Developer Edition:CSS网格调试
- Safari Web Inspector:iOS调试
20.3 协作工具
- Git:版本控制
- GitHub/GitLab:代码托管
- JIRA/Trello:项目管理
- Slack/Discord:团队沟通
21. 代码风格与团队协作
21.1 代码规范
- Airbnb JavaScript Style Guide:广泛采用的规范
- Google JavaScript Style Guide:另一种选择
- 团队统一:最重要的是团队内部一致
21.2 代码审查
- 关注可读性和可维护性
- 检查边界条件和错误处理
- 验证性能影响
- 提供建设性反馈
21.3 文档编写
- JSDoc:函数和API文档
/** * 计算两数之和 * @param {number} a - 第一个数 * @param {number} b - 第二个数 * @returns {number} 两数之和 */ function sum(a, b) { return a + b; } - README.md:项目概述和使用说明
- CHANGELOG.md:版本变更记录
22. 移动端与PWA开发
22.1 响应式设计
/* 媒体查询示例 */ @media (max-width: 768px) { .container { flex-direction: column; } }22.2 触摸事件
element.addEventListener('touchstart', handleTouch); element.addEventListener('touchmove', handleTouch); element.addEventListener('touchend', handleTouch); function handleTouch(e) { const touch = e.changedTouches[0]; console.log(touch.clientX, touch.clientY); }22.3 PWA特性
- Service Worker:离线缓存
- Web App Manifest:添加到主屏幕
- 推送通知:用户互动
// 注册Service Worker if ('serviceWorker' in navigator) { navigator.serviceWorker.register('/sw.js') .then(registration => { console.log('SW registered'); }); }23. 服务器端JavaScript
23.1 Node.js基础
// 简单HTTP服务器 const http = require('http'); const server = http.createServer((req, res) => { res.statusCode = 200; res.setHeader('Content-Type', 'text/plain'); res.end('Hello World\n'); }); server.listen(3000, () => { console.log('Server running at http://localhost:3000/'); });23.2 Express框架
const express = require('express'); const app = express(); app.get('/', (req, res) => { res.send('Hello Express!'); }); app.listen(3000, () => { console.log('Example app listening on port 3000!'); });23.3 数据库交互
// 使用MongoDB (Mongoose) const mongoose = require('mongoose'); mongoose.connect('mongodb://localhost/test'); const Schema = mongoose.Schema; const blogSchema = new Schema({ title: String, content: String }); const Blog = mongoose.model('Blog', blogSchema); // 创建新博客 Blog.create({ title: 'First Post', content: 'Hello World' });24. TypeScript入门
24.1 基本类型
let isDone: boolean = false; let decimal: number = 6; let color: string = "blue"; let list: number[] = [1, 2, 3]; // 接口 interface User { name: string; id: number; } const user: User = { name: "Alice", id: 1 };24.2 类与装饰器
class Greeter { greeting: string; constructor(message: string) { this.greeting = message; } greet() { return "Hello, " + this.greeting; } } // 装饰器 function sealed(constructor: Function) { Object.seal(constructor); Object.seal(constructor.prototype); } @sealed class Greeter { // ... }25. 性能分析与优化
25.1 基准测试
// 使用console.time console.time('array test'); const arr = []; for (let i = 0; i < 1000000; i++) { arr.push(i); } console.timeEnd('array test'); // 使用performance.now const start = performance.now(); // 执行代码 const end = performance.now(); console.log(`耗时: ${end - start} 毫秒`);25.2 内存管理
- 避免全局变量
- 及时清除定时器和事件监听
- 使用WeakMap/WeakSet管理对象引用
- 注意闭包中的内存泄漏
// 内存泄漏示例 function leakMemory() { const hugeArray = new Array(1000000).fill('*'); setInterval(() => { console.log(hugeArray.length); }, 1000); } // 改进版本 function noLeak() { const hugeArray = new Array(1000000).fill('*'); const intervalId = setInterval(() => { console.log(hugeArray.length); }, 1000); // 需要时清除 setTimeout(() => { clearInterval(intervalId); }, 5000); }26. 设计模式在JavaScript中的应用
26.1 常用设计模式
单例模式:
class Singleton { static instance; constructor() { if (Singleton.instance) { return Singleton.instance; } Singleton.instance = this; } } const s1 = new Singleton(); const s2 = new Singleton(); console.log(s1 === s2); // true观察者模式:
class Subject { constructor() { this.observers = []; } subscribe(observer) { this.observers.push(observer); } unsubscribe(observer) { this.observers = this.observers.filter(obs => obs !== observer); } notify(data) { this.observers.forEach(observer => observer.update(data)); } } class Observer { update(data) { console.log('Received data:', data); } }26.2 函数式编程模式
// 高阶函数 function multiplyBy(factor) { return function(number) { return number * factor; }; } const double = multiplyBy(2); console.log(double(5)); // 10 // 函数组合 const compose = (...fns) => x => fns.reduceRight((acc, fn) => fn(acc), x); const add5 = x => x + 5; const multiply2 = x => x * 2; const addThenMultiply = compose(multiply2, add5); console.log(addThenMultiply(3)); // (3 + 5) * 2 = 1627. 国际化与本地化
27.1 日期与时间格式化
// 使用Intl API const date = new Date(); console.log(new Intl.DateTimeFormat('en-US').format(date)); console.log(new Intl.DateTimeFormat('zh-CN').format(date)); // 相对时间格式化 const rtf = new Intl.RelativeTimeFormat('en', { numeric: 'auto' }); console.log(rtf.format(-1, 'day')); // "yesterday"27.2 多语言支持
// 简单实现 const translations = { en: { greeting: 'Hello', welcome: 'Welcome back' }, zh: { greeting: '你好', welcome: '欢迎回来' } }; function t(lang, key) { return translations[lang][key] || key; } console.log(t('zh', 'greeting')); // "你好"28. 图形与动画
28.1 Canvas基础
<canvas id="myCanvas" width="200" height="100"></canvas> <script> const canvas = document.getElementById('myCanvas'); const ctx = canvas.getContext('2d'); // 绘制矩形 ctx.fillStyle = 'red'; ctx.fillRect(10, 10, 50, 50); // 绘制路径 ctx.beginPath(); ctx.moveTo(75, 50); ctx.lineTo(100, 75); ctx.lineTo(100, 25); ctx.fill(); </script>28.2 动画实现
function animate() { const canvas = document.getElementById('myCanvas'); const ctx = canvas.getContext('2d'); let x = 0; function draw() { ctx.clearRect(0, 0, canvas.width, canvas.height); ctx.fillRect(x, 10, 50, 50); x += 1; if (x < canvas.width) { requestAnimationFrame(draw); } } draw(); } animate();29. Web组件与自定义元素
29.1 自定义元素
class MyElement extends HTMLElement { constructor() { super(); this.attachShadow({ mode: 'open' }); } connectedCallback() { this.shadowRoot.innerHTML = ` <style> p { color: blue; } </style> <p>Hello from custom element!</p> `; } } customElements.define('my-element', MyElement);<my-element></my-element>29.2 插槽(Slot)使用
class SlotElement extends HTMLElement { constructor() { super(); this.attachShadow({ mode: 'open' }); this.shadowRoot.innerHTML = ` <div> <h2><slot name="title">Default Title</slot></h2> <p><slot>Default content</slot></p> </div> `; } } customElements.define('slot-element', SlotElement);<slot-element> <span slot="title">Custom Title</span>