1. JavaScript 学习文档(三)核心内容解析
作为从业十年的前端开发者,我经常被问到如何系统性地掌握JavaScript核心概念。这个系列文档的第三部分,我们将深入探讨几个关键主题:对象操作、异步编程和函数式编程基础。这些内容不仅是面试高频考点,更是日常开发中必须掌握的实用技能。
2. JavaScript 对象深度操作
2.1 对象创建与属性管理
JavaScript对象是键值对的集合,创建方式多样:
javascript复制// 对象字面量
const user = {
name: 'John',
age: 30,
// 方法定义
sayHi() {
console.log(`Hello, ${this.name}!`);
}
};
// 构造函数
function Person(name, age) {
this.name = name;
this.age = age;
}
const person = new Person('Alice', 25);
重要提示:现代JavaScript推荐使用对象字面量语法,它更简洁且性能更好。仅在需要创建多个相似对象时才考虑构造函数。
属性描述符是对象操作的核心概念:
javascript复制Object.defineProperty(user, 'name', {
value: 'John',
writable: false, // 不可写
enumerable: true, // 可枚举
configurable: false // 不可配置
});
2.2 原型与继承机制
JavaScript采用原型继承而非类继承:
javascript复制// 原型链示例
const animal = {
eats: true
};
const rabbit = {
jumps: true,
__proto__: animal // 设置原型
};
console.log(rabbit.eats); // true (通过原型链访问)
ES6类语法糖:
javascript复制class Animal {
constructor(name) {
this.name = name;
}
speak() {
console.log(`${this.name} makes a noise.`);
}
}
class Dog extends Animal {
speak() {
super.speak();
console.log(`${this.name} barks.`);
}
}
3. 异步编程实战
3.1 Promise 核心用法
Promise解决了回调地狱问题:
javascript复制function loadScript(src) {
return new Promise((resolve, reject) => {
let script = document.createElement('script');
script.src = src;
script.onload = () => resolve(script);
script.onerror = () => reject(new Error(`Script load error for ${src}`));
document.head.append(script);
});
}
loadScript('/my/script.js')
.then(script => console.log(`${script.src} is loaded!`))
.catch(error => console.error(error));
3.2 async/await 最佳实践
现代异步代码首选方案:
javascript复制async function getUserData(userId) {
try {
const user = await fetchUser(userId);
const posts = await fetchPosts(user.id);
return { user, posts };
} catch (error) {
console.error('Failed to fetch data:', error);
throw error;
}
}
实战经验:await只能用在async函数中,但顶层await在模块中可以直接使用。合理使用Promise.all可以优化多个异步操作的并行执行。
4. 函数式编程基础
4.1 高阶函数应用
函数作为一等公民的典型用法:
javascript复制// 函数工厂
function createMultiplier(factor) {
return function(number) {
return number * factor;
};
}
const double = createMultiplier(2);
console.log(double(5)); // 10
// 数组高阶函数
const numbers = [1, 2, 3, 4];
const squared = numbers.map(x => x * x);
const evens = numbers.filter(x => x % 2 === 0);
const sum = numbers.reduce((acc, curr) => acc + curr, 0);
4.2 闭包与内存管理
闭包是JavaScript最强大的特性之一:
javascript复制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
内存泄漏警告:不当使用闭包会导致内存无法释放。确保及时解除不再需要的引用,特别是在DOM事件处理中。
5. 常见问题排查指南
5.1 作用域问题
javascript复制// 典型问题
for (var i = 0; i < 5; i++) {
setTimeout(() => console.log(i), 100); // 输出5个5
}
// 解决方案
for (let i = 0; i < 5; i++) {
setTimeout(() => console.log(i), 100); // 输出0-4
}
5.2 this绑定问题
javascript复制const obj = {
name: 'Object',
logName() {
console.log(this.name);
}
};
const log = obj.logName;
log(); // undefined (this丢失)
// 修复方案
const boundLog = obj.logName.bind(obj);
boundLog(); // 'Object'
5.3 异步执行顺序
javascript复制console.log('1');
setTimeout(() => console.log('2'), 0);
Promise.resolve().then(() => console.log('3'));
console.log('4');
// 输出顺序:1, 4, 3, 2
// 微任务(Promise)优先于宏任务(setTimeout)执行
6. 性能优化技巧
6.1 对象操作优化
javascript复制// 避免频繁属性查找
// 差
for (let i = 0; i < array.length; i++) { ... }
// 好
const length = array.length;
for (let i = 0; i < length; i++) { ... }
6.2 事件委托模式
javascript复制// 差
document.querySelectorAll('button').forEach(button => {
button.addEventListener('click', handleClick);
});
// 好
document.addEventListener('click', event => {
if (event.target.matches('button')) {
handleClick(event);
}
});
6.3 内存优化
javascript复制// WeakMap适合存储私有数据
const privateData = new WeakMap();
class MyClass {
constructor() {
privateData.set(this, {
secret: 123
});
}
getSecret() {
return privateData.get(this).secret;
}
}
7. 现代JavaScript特性
7.1 可选链操作符
javascript复制const user = {
address: {
street: 'Main St'
}
};
// 传统方式
const street = user && user.address && user.address.street;
// 现代方式
const street = user?.address?.street;
7.2 空值合并
javascript复制const config = {
timeout: 0
};
// 传统方式
const timeout = config.timeout !== undefined ? config.timeout : 1000;
// 现代方式
const timeout = config.timeout ?? 1000; // 0会被保留
7.3 解构赋值进阶
javascript复制// 嵌套解构
const user = {
id: 1,
name: 'John',
address: {
city: 'New York'
}
};
const {
name,
address: { city }
} = user;
// 函数参数解构
function drawChart({ size = 'big', coords = { x: 0, y: 0 } } = {}) {
console.log(size, coords);
}
8. 实战项目建议
8.1 待办事项应用
javascript复制class TodoApp {
constructor() {
this.todos = [];
this.nextId = 1;
}
addTodo(text) {
this.todos.push({
id: this.nextId++,
text,
completed: false
});
}
toggleTodo(id) {
const todo = this.todos.find(t => t.id === id);
if (todo) {
todo.completed = !todo.completed;
}
}
}
8.2 API请求封装
javascript复制class ApiClient {
constructor(baseURL) {
this.baseURL = baseURL;
}
async request(endpoint, options = {}) {
const response = await fetch(`${this.baseURL}${endpoint}`, {
headers: {
'Content-Type': 'application/json',
...options.headers
},
...options
});
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
return response.json();
}
get(endpoint) {
return this.request(endpoint);
}
post(endpoint, body) {
return this.request(endpoint, {
method: 'POST',
body: JSON.stringify(body)
});
}
}
9. 调试技巧
9.1 Chrome DevTools 高级用法
javascript复制// 条件断点
function processArray(arr) {
for (const item of arr) {
// 右键点击行号 -> Add conditional breakpoint
// 输入条件: item > 100
console.log(item);
}
}
// 日志点
// 右键点击行号 -> Add logpoint
// 输入: 'Current value:', item
9.2 性能分析
javascript复制// 标记时间点
console.time('myOperation');
// 执行操作
console.timeEnd('myOperation');
// 性能分析
function expensiveOperation() {
performance.mark('start');
// 复杂计算
performance.mark('end');
performance.measure('myMeasure', 'start', 'end');
const duration = performance.getEntriesByName('myMeasure')[0].duration;
console.log(`Operation took ${duration}ms`);
}
10. 测试驱动开发
10.1 Jest 基础测试
javascript复制// math.js
function sum(a, b) {
return a + b;
}
// math.test.js
test('adds 1 + 2 to equal 3', () => {
expect(sum(1, 2)).toBe(3);
});
test('async test', async () => {
const result = await fetchData();
expect(result).toEqual({ success: true });
});
10.2 模拟函数
javascript复制// userService.js
export async function fetchUser(id) {
const response = await fetch(`/users/${id}`);
return response.json();
}
// userService.test.js
import { fetchUser } from './userService';
jest.mock('./userService');
test('fetches user', async () => {
fetchUser.mockResolvedValue({ id: 1, name: 'John' });
const user = await fetchUser(1);
expect(user).toEqual({ id: 1, name: 'John' });
});
11. 安全最佳实践
11.1 XSS防护
javascript复制// 危险示例
const userInput = '<script>alert("XSS")</script>';
document.body.innerHTML = userInput;
// 安全处理
function sanitize(input) {
const div = document.createElement('div');
div.textContent = input;
return div.innerHTML;
}
document.body.textContent = sanitize(userInput);
11.2 CSRF防护
javascript复制// 后端应设置SameSite cookie
// 前端添加CSRF token
async function postData(url, data) {
const csrfToken = document.querySelector('meta[name="csrf-token"]').content;
const response = await fetch(url, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-CSRF-Token': csrfToken
},
body: JSON.stringify(data)
});
return response.json();
}
12. 模块化开发
12.1 ES Modules
javascript复制// math.js
export function sum(a, b) {
return a + b;
}
// app.js
import { sum } from './math.js';
console.log(sum(1, 2));
12.2 动态导入
javascript复制// 按需加载
button.addEventListener('click', async () => {
const module = await import('./dialog.js');
module.openDialog();
});
13. 工具链配置
13.1 Babel 配置
json复制// .babelrc
{
"presets": [
["@babel/preset-env", {
"targets": "> 0.25%, not dead",
"useBuiltIns": "usage",
"corejs": 3
}]
],
"plugins": ["@babel/plugin-transform-runtime"]
}
13.2 ESLint 规则
json复制// .eslintrc.json
{
"extends": ["eslint:recommended", "airbnb-base"],
"rules": {
"no-console": "warn",
"arrow-parens": ["error", "as-needed"],
"comma-dangle": ["error", "never"]
}
}
14. 性能监控
14.1 Web Vitals 指标
javascript复制import { getCLS, getFID, getLCP } from 'web-vitals';
getCLS(console.log);
getFID(console.log);
getLCP(console.log);
14.2 错误追踪
javascript复制window.addEventListener('error', (event) => {
fetch('/log-error', {
method: 'POST',
body: JSON.stringify({
message: event.message,
stack: event.error.stack,
url: window.location.href
})
});
});
15. 设计模式应用
15.1 观察者模式
javascript复制class EventEmitter {
constructor() {
this.events = {};
}
on(event, listener) {
if (!this.events[event]) {
this.events[event] = [];
}
this.events[event].push(listener);
}
emit(event, ...args) {
if (this.events[event]) {
this.events[event].forEach(listener => listener(...args));
}
}
}
15.2 单例模式
javascript复制class Logger {
constructor() {
if (!Logger.instance) {
this.logs = [];
Logger.instance = this;
}
return Logger.instance;
}
log(message) {
this.logs.push(message);
console.log(message);
}
}
const logger1 = new Logger();
const logger2 = new Logger();
console.log(logger1 === logger2); // true
16. Web Workers 应用
16.1 主线程代码
javascript复制const worker = new Worker('worker.js');
worker.postMessage({ type: 'CALCULATE', data: largeArray });
worker.onmessage = (event) => {
console.log('Result:', event.data);
};
16.2 Worker 线程代码
javascript复制// worker.js
self.onmessage = (event) => {
if (event.data.type === 'CALCULATE') {
const result = heavyCalculation(event.data.data);
self.postMessage(result);
}
};
function heavyCalculation(data) {
// 复杂计算
return processedData;
}
17. 类型检查与TypeScript
17.1 JSDoc 类型注释
javascript复制/**
* 计算两个数字的和
* @param {number} a 第一个数字
* @param {number} b 第二个数字
* @returns {number} 两数之和
*/
function sum(a, b) {
return a + b;
}
17.2 TypeScript 接口
typescript复制interface User {
id: number;
name: string;
email?: string; // 可选属性
}
function greet(user: User) {
console.log(`Hello, ${user.name}`);
}
18. 动画与图形
18.1 requestAnimationFrame
javascript复制function animate() {
const element = document.getElementById('box');
let position = 0;
function step(timestamp) {
position += 1;
element.style.left = position + 'px';
if (position < 200) {
window.requestAnimationFrame(step);
}
}
window.requestAnimationFrame(step);
}
18.2 Canvas 绘图
javascript复制const canvas = document.getElementById('myCanvas');
const ctx = canvas.getContext('2d');
ctx.fillStyle = 'green';
ctx.fillRect(10, 10, 100, 100);
ctx.beginPath();
ctx.arc(150, 75, 50, 0, Math.PI * 2);
ctx.stroke();
19. Web Components
19.1 自定义元素
javascript复制class MyElement extends HTMLElement {
constructor() {
super();
this.attachShadow({ mode: 'open' });
this.shadowRoot.innerHTML = `
<style>
:host {
display: block;
padding: 16px;
background: #f0f0f0;
}
</style>
<div>Hello, <slot></slot></div>
`;
}
}
customElements.define('my-element', MyElement);
19.2 属性观察
javascript复制class MyElement extends HTMLElement {
static get observedAttributes() {
return ['name'];
}
attributeChangedCallback(name, oldValue, newValue) {
if (name === 'name') {
this.shadowRoot.querySelector('div').textContent = `Hello, ${newValue}`;
}
}
}
20. 现代框架概念
20.1 虚拟DOM原理
javascript复制// 简化的虚拟DOM实现
function createElement(type, props, ...children) {
return {
type,
props: {
...props,
children: children.map(child =>
typeof child === 'object' ? child : createTextElement(child)
)
}
};
}
function createTextElement(text) {
return {
type: 'TEXT_ELEMENT',
props: {
nodeValue: text,
children: []
}
};
}
20.2 响应式原理
javascript复制// 简化的响应式实现
function reactive(obj) {
const handlers = {
get(target, key) {
track(target, key);
return Reflect.get(target, key);
},
set(target, key, value) {
Reflect.set(target, key, value);
trigger(target, key);
return true;
}
};
return new Proxy(obj, handlers);
}
const state = reactive({ count: 0 });
function track(target, key) {
// 记录依赖
}
function trigger(target, key) {
// 触发更新
}
21. 工程化实践
21.1 代码分割
javascript复制// 动态导入实现代码分割
const button = document.getElementById('load-component');
button.addEventListener('click', () => {
import('./heavy-component.js')
.then(module => {
module.render();
})
.catch(err => {
console.error('加载失败:', err);
});
});
21.2 Tree Shaking
javascript复制// 确保使用ES模块语法
export function usedFunction() {
console.log('I am used');
}
export function unusedFunction() {
console.log('I will be removed');
}
// 导入时只导入需要的函数
import { usedFunction } from './utils.js';
22. 调试进阶技巧
22.1 性能瓶颈分析
javascript复制// 使用performance API进行精确测量
function measureOperation() {
performance.mark('start');
// 执行需要测量的操作
for (let i = 0; i < 1000000; i++) {
Math.sqrt(i);
}
performance.mark('end');
performance.measure('myOperation', 'start', 'end');
const measures = performance.getEntriesByName('myOperation');
console.log(`操作耗时: ${measures[0].duration}ms`);
}
22.2 内存泄漏检测
javascript复制// 使用Chrome DevTools的Memory面板
// 1. 记录堆快照
// 2. 执行操作
// 3. 再次记录堆快照
// 4. 比较快照,查找未释放的对象
// 常见内存泄漏模式
function createLeak() {
const hugeArray = new Array(1000000).fill('leak');
// 闭包保持引用
setInterval(() => {
console.log(hugeArray.length);
}, 1000);
}
23. 浏览器API进阶
23.1 Intersection Observer
javascript复制// 懒加载实现
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
const img = entry.target;
img.src = img.dataset.src;
observer.unobserve(img);
}
});
});
document.querySelectorAll('img[data-src]').forEach(img => {
observer.observe(img);
});
23.2 Web Storage
javascript复制// localStorage封装
const storage = {
get(key) {
try {
return JSON.parse(localStorage.getItem(key));
} catch (e) {
return null;
}
},
set(key, value) {
localStorage.setItem(key, JSON.stringify(value));
},
remove(key) {
localStorage.removeItem(key);
}
};
// 使用
storage.set('user', { name: 'John' });
const user = storage.get('user');
24. 函数式编程进阶
24.1 柯里化
javascript复制function curry(fn) {
return function curried(...args) {
if (args.length >= fn.length) {
return fn.apply(this, args);
} else {
return function(...args2) {
return curried.apply(this, args.concat(args2));
};
}
};
}
const sum = (a, b, c) => a + b + c;
const curriedSum = curry(sum);
console.log(curriedSum(1)(2)(3)); // 6
24.2 函数组合
javascript复制const compose = (...fns) => x => fns.reduceRight((v, f) => f(v), x);
const toUpperCase = str => str.toUpperCase();
const exclaim = str => `${str}!`;
const shout = compose(exclaim, toUpperCase);
console.log(shout('hello')); // "HELLO!"
25. 正则表达式实战
25.1 常用模式
javascript复制// 邮箱验证
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
console.log(emailRegex.test('test@example.com')); // true
// 提取URL参数
const url = 'https://example.com?name=John&age=30';
const params = {};
url.match(/([^?=&]+)(=([^&]*))?/g).forEach(pair => {
const [key, value] = pair.split('=');
params[key] = value;
});
console.log(params); // { name: 'John', age: '30' }
25.2 高级技巧
javascript复制// 命名捕获组
const dateRegex = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/;
const match = dateRegex.exec('2023-05-15');
console.log(match.groups); // { year: '2023', month: '05', day: '15' }
// 正向/负向断言
const passwordRegex = /^(?=.*[A-Z])(?=.*\d).{8,}$/;
console.log(passwordRegex.test('Password1')); // true
26. 数据结构实现
26.1 链表
javascript复制class ListNode {
constructor(value) {
this.value = value;
this.next = null;
}
}
class LinkedList {
constructor() {
this.head = null;
this.tail = null;
}
append(value) {
const node = new ListNode(value);
if (!this.head) {
this.head = node;
this.tail = node;
} else {
this.tail.next = node;
this.tail = node;
}
}
}
26.2 哈希表
javascript复制class HashTable {
constructor(size = 32) {
this.buckets = new Array(size);
this.size = size;
}
hash(key) {
let hash = 0;
for (let i = 0; i < key.length; i++) {
hash = (hash << 5) + key.charCodeAt(i);
hash = hash & hash; // Convert to 32bit integer
hash = Math.abs(hash);
}
return hash % this.size;
}
set(key, value) {
const index = this.hash(key);
if (!this.buckets[index]) {
this.buckets[index] = [];
}
this.buckets[index].push([key, value]);
}
}
27. 算法实战
27.1 排序算法
javascript复制// 快速排序
function quickSort(arr) {
if (arr.length <= 1) return arr;
const pivot = arr[0];
const left = [];
const right = [];
for (let i = 1; i < arr.length; i++) {
if (arr[i] < pivot) {
left.push(arr[i]);
} else {
right.push(arr[i]);
}
}
return [...quickSort(left), pivot, ...quickSort(right)];
}
27.2 二分查找
javascript复制function binarySearch(arr, target) {
let left = 0;
let right = arr.length - 1;
while (left <= right) {
const mid = Math.floor((left + right) / 2);
if (arr[mid] === target) {
return mid;
} else if (arr[mid] < target) {
left = mid + 1;
} else {
right = mid - 1;
}
}
return -1;
}
28. 设计系统基础
28.1 样式封装
javascript复制// CSS-in-JS 示例
function styled(element) {
return (styles) => {
const el = document.createElement(element);
el.style = styles;
return el;
};
}
const Button = styled('button')`
background: blue;
color: white;
padding: 8px 16px;
border: none;
border-radius: 4px;
`;
document.body.appendChild(Button);
28.2 主题管理
javascript复制// 主题上下文
const ThemeContext = React.createContext('light');
function App() {
return (
<ThemeContext.Provider value="dark">
<Toolbar />
</ThemeContext.Provider>
);
}
function Toolbar() {
return (
<div>
<ThemedButton />
</div>
);
}
function ThemedButton() {
const theme = React.useContext(ThemeContext);
return <button className={theme}>Themed Button</button>;
}
29. 服务端JavaScript
29.1 Express 基础
javascript复制const express = require('express');
const app = express();
app.use(express.json());
app.get('/api/users', (req, res) => {
res.json([{ id: 1, name: 'John' }]);
});
app.post('/api/users', (req, res) => {
const user = req.body;
// 保存用户
res.status(201).json(user);
});
app.listen(3000, () => {
console.log('Server running on port 3000');
});
29.2 中间件模式
javascript复制// 日志中间件
function logger(req, res, next) {
console.log(`${req.method} ${req.url}`);
next();
}
// 错误处理中间件
function errorHandler(err, req, res, next) {
console.error(err.stack);
res.status(500).send('Something broke!');
}
app.use(logger);
app.use(errorHandler);
30. 测试进阶
30.1 快照测试
javascript复制// Jest 快照测试
test('renders correctly', () => {
const component = renderer.create(<MyComponent />);
const tree = component.toJSON();
expect(tree).toMatchSnapshot();
});
30.2 E2E 测试
javascript复制// Cypress 示例
describe('Login', () => {
it('should login successfully', () => {
cy.visit('/login');
cy.get('#username').type('testuser');
cy.get('#password').type('password');
cy.get('button[type="submit"]').click();
cy.url().should('include', '/dashboard');
});
});
31. 构建优化
31.1 代码分割策略
javascript复制// webpack 动态导入
const path = require('path');
module.exports = {
entry: {
main: './src/index.js',
vendor: ['react', 'react-dom']
},
output: {
filename: '[name].[contenthash].js',
path: path.resolve(__dirname, 'dist')
},
optimization: {
splitChunks: {
chunks: 'all'
}
}
};
31.2 缓存策略
javascript复制// Service Worker 缓存
self.addEventListener('install', (event) => {
event.waitUntil(
caches.open('v1').then((cache) => {
return cache.addAll([
'/',
'/index.html',
'/styles/main.css',
'/scripts/main.js'
]);
})
);
});
self.addEventListener('fetch', (event) => {
event.respondWith(
caches.match(event.request).then((response) => {
return response || fetch(event.request);
})
);
});
32. 国际化方案
32.1 i18n 实现
javascript复制// 简单国际化方案
const translations = {
en: {
greeting: 'Hello',
welcome: 'Welcome back, {name}!'
},
fr: {
greeting: 'Bonjour',
welcome: 'Bienvenue, {name}!'
}
};
function t(key, lang = 'en', params = {}) {
let text = translations[lang][key] || translations.en[key];
Object.keys(params).forEach(k => {
text = text.replace(`{${k}}`, params[k]);
});
return text;
}
console.log(t('welcome', 'fr', { name: 'John' })); // "Bienvenue, John!"
32.2 日期本地化
javascript复制const date = new Date();
console.log(date.toLocaleDateString('en-US')); // "5/15/2023"
console.log(date.toLocaleDateString('fr-FR')); // "15/05/2023"
console.log(date.toLocaleDateString('ja-JP')); // "2023/5/15"
33. 安全进阶
33.1 CSP 策略
html复制<!-- Content Security Policy -->
<meta http-equiv="Content-Security-Policy" content="
default-src 'self';
script-src 'self' 'unsafe-inline' https://cdn.example.com;
style-src 'self' 'unsafe-inline';
img-src 'self' data: https://*.example.com;
">
33.2 JWT 认证
javascript复制// JWT 验证中间件
function authenticate(req, res, next) {
const token = req.headers.authorization?.split(' ')[1];
if (!token) return res.sendStatus(401);
try {
const decoded = jwt.verify(token, process.env.JWT_SECRET);
req.user = decoded;
next();
} catch (err) {
return res.sendStatus(403);
}
}
34. 移动端适配
34.1 响应式设计
javascript复制// 设备检测
function isMobile() {
return /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(
navigator.userAgent
);
}
// 视口设置
const meta = document.createElement('meta');
meta.name = 'viewport';
meta.content = 'width=device-width, initial-scale=1, maximum-scale=1';
document.head.appendChild(meta);
34.2 触摸事件
javascript复制// 手势检测
const element = document.getElementById('swipe-area');
let startX, startY;
element.addEventListener('touchstart', (e) => {
startX = e.touches[0].clientX;
startY = e.touches[0].clientY;
});
element.addEventListener('touchmove', (e) => {
const x = e.touches[0].clientX;
const y = e.touches[0].clientY;
const dx = x - startX;
const dy = y - startY;
if (Math.abs(dx) > Math.abs(dy)) {
console.log(dx > 0 ? '右滑' : '左滑');
} else {
console.log(dy > 0 ? '下滑' : '上滑');
}
});
35. WebAssembly 入门
35.1 加载WASM模块
javascript复制// 加载并实例化WASM模块
async function loadWasm() {
const response = await fetch('module.wasm');
const buffer = await response.arrayBuffer();
const module = await WebAssembly.compile(buffer);
const instance = await WebAssembly.instantiate(module);
return instance.exports;
}
loadWasm().then(exports => {
console.log(exports.add(1, 2)); // 调用WASM函数
});
35.2 与JS交互
javascript复制// WASM模块 (C代码)
// int add(int a, int b) { return a + b; }
// JavaScript调用
const imports = {
env: {
memory: new WebAssembly.Memory({ initial: 256 }),
table: new WebAssembly.Table({ initial: 0, element: 'anyfunc' })
}
};
WebAssembly.instantiateStreaming(fetch('add.wasm'), imports)
.then(obj => {
console.log(obj.instance.exports.add(1, 2)); // 3
});
36. 状态管理方案
36.1 Redux 核心概念
javascript复制// Reducer
function counter(state = 0, action) {
switch (action.type) {
case 'INCREMENT':
return state + 1;
case 'DECREMENT':
return state - 1;
default:
return state;
}
}
// Store
const store = Redux.createStore(counter);
// Dispatch
store.dispatch({ type: 'INCREMENT' });
console.log(store.getState()); // 1
36.2 Context API
javascript复制// 创建Context
const CountContext = React.createContext();
function App() {
const [count, setCount] = useState(0);
return (
<CountContext.Provider value={{ count, setCount }}>
<ChildComponent />
</CountContext.Provider>
);
}
function ChildComponent() {
const { count, setCount } = useContext(CountContext);
return (
<button onClick={() => setCount(c => c + 1)}>
Count: {count}
</button>
);
}
37. 数据可视化
37.1 Chart.js 基础
javascript复制const ctx = document.getElementById
