函数or块级作用域
块级作用域:变量在块外不可访问
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| if (true) { let x = 1; const y = 2; }
for (let i = 0; i < 3; i++) { let value = i * 2; }
{ let x = 1; const y = 2; }
|
函数作用域:变量在函数外部不可访问
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| function compare() { var x = 1; if (true) { var x = 2; let y = 3; console.log(x); console.log(y); } console.log(x); }
|
对比下面的例子
1 2 3 4 5 6 7 8 9 10 11 12
| for(var i = 0; i < 3; i++) { setTimeout(() => { console.log(i); }, 1000); }
for(let i = 0; i < 3; i++) { setTimeout(() => { console.log(i); }, 1000); }
|
避免闭包陷阱
setTimeout(callback,delay)
:执行的函数,延迟时间(毫秒)
使用 var
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| console.log('循环开始');
for(var i = 0; i < 3; i++) { setTimeout(() => { console.log(i); }, 1000); console.log('当前i:', i); }
console.log('循环结束,此时i:', i);
|
相当于
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| var i;
i = 0; setTimeout(() => { console.log(i); }, 1000);
i = 1; setTimeout(() => { console.log(i); }, 1000);
i = 2; setTimeout(() => { console.log(i); }, 1000);
i = 3;
|
使用 let
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| console.log('循环开始');
for(let i = 0; i < 3; i++) { setTimeout(() => { console.log(i); }, 1000); console.log('当前i:', i); }
|
相当于
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| { let i = 0; setTimeout(() => { console.log(i); }, 1000); }
{ let i = 1; setTimeout(() => { console.log(i); }, 1000); }
{ let i = 2; setTimeout(() => { console.log(i); }, 1000); }
|
其他解决 var
的问题
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| for(var i = 0; i < 3; i++) { (function(j) { setTimeout(() => { console.log(j); }, 1000); })(i); }
for(var i = 0; i < 3; i++) { setTimeout((j) => { console.log(j); }, 1000, i); }
|
React 状态更新方式对比
1 2 3 4 5 6 7 8 9 10 11
| const handleDirectUpdate = () => { setDirectCount(directCount + 1); setDirectCount(directCount + 1); setDirectCount(directCount + 1); }; const handleFunctionalUpdate = () => { setFuncCount(prev => prev + 1); setFuncCount(prev => prev + 1); setFuncCount(prev => prev + 1); };
|
下面是上述代码演示,可以点击按钮来体验两种不同的状态更新方式
JS对象迭代特性
for…in的陷阱
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| const parent = { parentMethod: function() {} };
const child = Object.create(parent); child.name = '张三'; child.age = 25;
console.log('===for...in遍历==='); for(let key in child) { console.log(key); }
console.log('===使用hasOwnProperty==='); for(let key in child) { if(child.hasOwnProperty(key)) { console.log(key); } }
|
Object.keys()和Object.entries()
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| const person = { name: '张三', age: 25 };
Object.defineProperty(person, 'password', { value: '123456', enumerable: false });
console.log('===Object.keys()==='); console.log(Object.keys(person));
console.log('===Object.entries()==='); Object.entries(person).forEach(([key, value]) => { console.log(`${key}: ${value}`); });
|
Object.getOwnPropertyDescriptor()查看属性特性
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| const obj = {};
Object.defineProperty(obj, 'name', { value: '张三', writable: true, enumerable: true, configurable: true });
console.log('===属性描述符==='); console.log(Object.getOwnPropertyDescriptor(obj, 'name'));
|
迭代器与生成器的高级用法
自定义可迭代对象
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| const courses = { _list: ['JavaScript', 'Python', 'Java'], [Symbol.iterator]() { let index = 0; const self = this; return { next() { if (index < self._list.length) { return { value: self._list[index++], done: false }; } return { done: true }; } }; } };
console.log('===课程列表遍历==='); for(let course of courses) { console.log(course); }
|
生成器函数的实际应用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53
| function* createPageGenerator(totalItems, pageSize) { const totalPages = Math.ceil(totalItems / pageSize); for(let page = 1; page <= totalPages; page++) { const start = (page - 1) * pageSize; const end = Math.min(start + pageSize, totalItems); yield { page, start, end, isLastPage: page === totalPages }; } }
const pageGen = createPageGenerator(95, 10); console.log('===分页示例==='); for(let pageInfo of pageGen) { console.log(`第${pageInfo.page}页: ${pageInfo.start}-${pageInfo.end}`); }
function* traverseTree(node) { yield node.value; if(node.children) { for(let child of node.children) { yield* traverseTree(child); } } }
const tree = { value: 'root', children: [ { value: 'A', children: [ { value: 'A1' }, { value: 'A2' } ] }, { value: 'B' } ] };
console.log('===树形遍历==='); for(let value of traverseTree(tree)) { console.log(value); }
|
async迭代器的实战应用
异步数据流处理
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53
| async function* asyncDataSource() { const data = [ { id: 1, name: '用户1' }, { id: 2, name: '用户2' }, { id: 3, name: '用户3' } ]; for(let item of data) { await new Promise(resolve => setTimeout(resolve, 1000)); yield item; } }
async function processUsers() { console.log('===开始处理用户数据==='); for await (let user of asyncDataSource()) { console.log(`处理用户: ${user.name}`); } console.log('===用户数据处理完成==='); }
async function* fetchPaginatedData(url, pageSize = 10) { let page = 1; let hasMore = true; while(hasMore) { const response = await fetch( `${url}?page=${page}&pageSize=${pageSize}` ); const data = await response.json(); yield data.items; hasMore = data.hasMore; page++; } }
async function downloadAllData() { try { for await (let pageData of fetchPaginatedData('/api/data')) { console.log('获取到一页数据:', pageData); } } catch(error) { console.error('数据获取失败:', error); } }
|
实用的迭代器工具函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
| async function* mergeAsyncIterators(...iterators) { const promises = iterators.map(async iterator => { for await (let item of iterator) { yield item; } }); await Promise.all(promises); }
async function* mapAsyncIterator(iterator, mapFn) { for await (let item of iterator) { yield mapFn(item); } }
async function* filterAsyncIterator(iterator, filterFn) { for await (let item of iterator) { if (await filterFn(item)) { yield item; } } }
async function demo() { const asyncData = asyncDataSource(); const transformedData = mapAsyncIterator( asyncData, item => ({ ...item, processed: true }) ); const filteredData = filterAsyncIterator( transformedData, async item => item.id > 1 ); for await (let item of filteredData) { console.log('处理后的数据:', item); } }
|
for循环和forEach的性能对比
执行速度对比
1 2 3 4 5 6 7 8 9 10 11 12 13
| const largeArray = Array(1000000).fill(1);
console.time('for'); for(let i = 0; i < largeArray.length; i++) { const item = largeArray[i]; } console.timeEnd('for');
console.time('forEach'); largeArray.forEach(item => { const temp = item; }); console.timeEnd('forEach');
|
中断执行的差异
1 2 3 4 5 6 7 8 9 10 11
| for(let i = 0; i < 5; i++) { if(i === 3) break; console.log(i); }
[1,2,3,4,5].forEach(num => { if(num === 3) return; console.log(num); });
|
map配合Promise.all的异步处理
并行请求处理
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| async function fetchUserData(users) { try { const requests = users.map(user => fetch(`/api/users/${user.id}`) ); const responses = await Promise.all(requests); const data = await Promise.all( responses.map(res => res.json()) ); return data; } catch (error) { console.error('数据获取失败:', error); return []; } }
const users = [ { id: 1 }, { id: 2 }, { id: 3 } ];
fetchUserData(users).then(data => { console.log('获取的用户数据:', data); });
|
数据清洗
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| const rawData = [ { id: 1, name: ' John ', age: '20' }, { id: 2, name: 'Jane ', age: '25' }, { id: 3, name: ' Bob', age: '30' } ];
const cleanData = rawData.map(item => ({ id: item.id, name: item.name.trim(), age: parseInt(item.age), createdAt: new Date() }));
console.log('清洗后的数据:', cleanData);
|
filter和map链式调用
数据筛选和转换
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| const products = [ { id: 1, name: '手机', price: 2999, stock: 0 }, { id: 2, name: '电脑', price: 5999, stock: 10 }, { id: 3, name: '耳机', price: 999, stock: 5 }, { id: 4, name: '平板', price: 3999, stock: 3 } ];
const availableProducts = products .filter(product => product.stock > 0) .map(product => ({ id: product.id, name: product.name, price: `¥${product.price.toFixed(2)}`, inStock: true }));
console.log('可购买商品:', availableProducts);
|
条件过滤和数据转换
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| const messages = [ { type: 'error', content: '操作失败', code: 500 }, { type: 'success', content: '保存成功', code: 200 }, { type: 'warning', content: '即将超时', code: 0 }, { type: 'error', content: '网络错误', code: 503 } ];
const errorLogs = messages .filter(msg => msg.type === 'error') .map(error => ({ message: error.content, time: new Date().toISOString(), code: error.code }));
console.log('错误日志:', errorLogs);
|
reduce方法的高级应用
数组转对象
1 2 3 4 5 6 7 8 9 10 11 12 13
| const users = [ { id: 1, name: '张三', age: 20 }, { id: 2, name: '李四', age: 25 }, { id: 3, name: '王五', age: 22 } ];
const userMap = users.reduce((acc, user) => { acc[user.id] = user; return acc; }, {});
console.log('用户映射:', userMap);
|
分组统计
1 2 3 4 5 6 7 8 9 10 11 12 13
| const orders = [ { date: '2024-01-01', amount: 100 }, { date: '2024-01-01', amount: 200 }, { date: '2024-01-02', amount: 300 } ];
const dailyTotal = orders.reduce((acc, order) => { acc[order.date] = (acc[order.date] || 0) + order.amount; return acc; }, {});
console.log('每日订单总额:', dailyTotal);
|
every结合Object.values的应用
表单验证
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| const formData = { username: 'john_doe', email: 'john@example.com', age: '25' };
const validations = { username: value => value.length >= 3, email: value => value.includes('@'), age: value => !isNaN(value) && parseInt(value) > 0 };
const isValid = Object.entries(validations) .every(([field, validate]) => { const value = formData[field]; return validate(value); });
console.log('表单是否有效:', isValid);
|
some和every的对比使用
权限检查
1 2 3 4 5 6 7 8 9 10 11 12
| const userRoles = ['editor', 'viewer'];
const hasAnyRequiredRole = userRoles .some(role => ['admin', 'editor'].includes(role));
const hasAllRequiredRoles = ['viewer', 'editor'] .every(role => userRoles.includes(role));
console.log('有任一所需权限:', hasAnyRequiredRole); console.log('有所有所需权限:', hasAllRequiredRoles);
|
includes的组合应用
标签匹配
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| const posts = [ { id: 1, tags: ['javascript', 'tutorial'] }, { id: 2, tags: ['python', 'data-science'] }, { id: 3, tags: ['javascript', 'react'] } ];
const requiredTags = ['javascript', 'tutorial'];
const matchedPosts = posts.filter(post => requiredTags.every(tag => post.tags.includes(tag)) );
console.log('匹配的文章:', matchedPosts);
|
高级应用场景
组合使用多种方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| const orders = [ { id: 1, items: ['apple', 'banana'], total: 50 }, { id: 2, items: ['orange'], total: 30 }, { id: 3, items: ['banana', 'grape'], total: 45 } ];
const result = orders .filter(order => order.total > 40) .map(order => ({ id: order.id, itemCount: order.items.length, hasSpecialItem: order.items.includes('banana') })) .reduce((acc, order) => { acc.totalOrders++; acc.specialOrders += order.hasSpecialItem ? 1 : 0; return acc; }, { totalOrders: 0, specialOrders: 0 });
console.log('订单统计:', result);
|