大厂做网站/关键词推广seo怎么优化
JavaScript 数组与引用类型语法知识点及案例代码
一、认识引用类型
在JavaScript中,数据类型分为基本类型和引用类型。数组属于引用类型,这意味着:
- 基本类型(Number, String, Boolean, Null, Undefined, Symbol)直接存储值
- 引用类型(Array, Object, Function)存储的是内存地址
// 基本类型示例
let a = 10;
let b = a; // b获取的是a的值的一个副本
a = 20;
console.log(b); // 10,b不受a后续变化的影响// 引用类型示例
let arr1 = [1, 2, 3];
let arr2 = arr1; // arr2和arr1指向同一个内存地址
arr1.push(4);
console.log(arr2); // [1, 2, 3, 4],arr2会随着arr1的变化而变化
二、数组基础
1. 什么是数组
数组是用于存储多个值的单一对象,每个值称为一个元素,元素可以是任意数据类型。
2. 定义数组
// 1. 数组字面量(推荐)
let fruits = ['Apple', 'Banana', 'Orange'];// 2. Array构造函数
let numbers = new Array(1, 2, 3);// 3. 指定长度的空数组
let emptyArray = new Array(5); // 创建长度为5的空数组console.log(fruits); // ["Apple", "Banana", "Orange"]
console.log(numbers); // [1, 2, 3]
console.log(emptyArray); // [empty × 5]
三、数组元素操作
1. 访问元素
let colors = ['red', 'green', 'blue'];// 通过索引访问(从0开始)
console.log(colors[0]); // "red"
console.log(colors[2]); // "blue"// 访问不存在的索引返回undefined
console.log(colors[3]); // undefined
2. 修改元素
let colors = ['red', 'green', 'blue'];// 修改指定索引的元素
colors[1] = 'yellow';
console.log(colors); // ["red", "yellow", "blue"]// 添加新元素到数组末尾
colors[3] = 'purple';
console.log(colors); // ["red", "yellow", "blue", "purple"]
3. 数组长度
let languages = ['JavaScript', 'Python', 'Java'];// 获取数组长度
console.log(languages.length); // 3// 修改length属性可以截断或扩展数组
languages.length = 2;
console.log(languages); // ["JavaScript", "Python"]languages.length = 4;
console.log(languages); // ["JavaScript", "Python", empty × 2]
四、数组遍历
1. for循环
let numbers = [10, 20, 30, 40];// 传统for循环
for (let i = 0; i < numbers.length; i++) {console.log(`Index ${i}: ${numbers[i]}`);
}
2. for…of循环
let fruits = ['Apple', 'Banana', 'Orange'];// for...of循环(直接获取元素值)
for (let fruit of fruits) {console.log(fruit);
}
3. forEach方法
let colors = ['red', 'green', 'blue'];// forEach方法
colors.forEach(function(color, index) {console.log(`Color at index ${index} is ${color}`);
});
五、数组元素定位
1. indexOf / lastIndexOf
let numbers = [1, 2, 3, 4, 3, 5];// 查找元素第一次出现的索引
console.log(numbers.indexOf(3)); // 2// 查找元素最后一次出现的索引
console.log(numbers.lastIndexOf(3)); // 4// 找不到返回-1
console.log(numbers.indexOf(10)); // -1
2. find / findIndex
let users = [{id: 1, name: 'John'},{id: 2, name: 'Jane'},{id: 3, name: 'Bob'}
];// find返回第一个满足条件的元素
let user = users.find(item => item.id === 2);
console.log(user); // {id: 2, name: "Jane"}// findIndex返回第一个满足条件的元素的索引
let index = users.findIndex(item => item.name === 'Bob');
console.log(index); // 2
3. includes
let fruits = ['Apple', 'Banana', 'Orange'];// 检查数组是否包含某个元素
console.log(fruits.includes('Banana')); // true
console.log(fruits.includes('Grape')); // false
六、数组排序
1. sort方法
let numbers = [3, 1, 4, 2, 5];// 默认排序(按字符串Unicode码点)
numbers.sort();
console.log(numbers); // [1, 2, 3, 4, 5]// 自定义排序
let scores = [95, 70, 88, 60, 100];
scores.sort((a, b) => a - b); // 升序
console.log(scores); // [60, 70, 88, 95, 100]scores.sort((a, b) => b - a); // 降序
console.log(scores); // [100, 95, 88, 70, 60]
2. reverse方法
let letters = ['a', 'b', 'c', 'd'];// 反转数组
letters.reverse();
console.log(letters); // ["d", "c", "b", "a"]
七、数组相关方法
1. 添加/删除元素
let fruits = ['Apple', 'Banana'];// push - 末尾添加
fruits.push('Orange');
console.log(fruits); // ["Apple", "Banana", "Orange"]// pop - 末尾删除
let last = fruits.pop();
console.log(last); // "Orange"
console.log(fruits); // ["Apple", "Banana"]// unshift - 开头添加
fruits.unshift('Grape');
console.log(fruits); // ["Grape", "Apple", "Banana"]// shift - 开头删除
let first = fruits.shift();
console.log(first); // "Grape"
console.log(fruits); // ["Apple", "Banana"]
2. splice方法
let numbers = [1, 2, 3, 4, 5];// 删除元素
let removed = numbers.splice(1, 2); // 从索引1开始删除2个元素
console.log(removed); // [2, 3]
console.log(numbers); // [1, 4, 5]// 添加元素
numbers.splice(1, 0, 'a', 'b'); // 从索引1开始删除0个元素,添加'a','b'
console.log(numbers); // [1, "a", "b", 4, 5]// 替换元素
numbers.splice(2, 1, 'c'); // 从索引2开始删除1个元素,添加'c'
console.log(numbers); // [1, "a", "c", 4, 5]
3. slice方法
let colors = ['red', 'green', 'blue', 'yellow', 'purple'];// 截取数组
let subColors = colors.slice(1, 4); // 从索引1到索引4(不包括4)
console.log(subColors); // ["green", "blue", "yellow"]// 复制数组
let copy = colors.slice();
console.log(copy); // ["red", "green", "blue", "yellow", "purple"]
4. concat方法
let arr1 = [1, 2];
let arr2 = [3, 4];// 合并数组
let combined = arr1.concat(arr2);
console.log(combined); // [1, 2, 3, 4]// 合并多个数组或值
let arr3 = [5, 6];
let all = arr1.concat(arr2, arr3, 7);
console.log(all); // [1, 2, 3, 4, 5, 6, 7]
5. join方法
let names = ['John', 'Jane', 'Bob'];// 数组转字符串
let str = names.join(', ');
console.log(str); // "John, Jane, Bob"// 空join
console.log(names.join()); // "John,Jane,Bob"
console.log(names.join('')); // "JohnJaneBob"
6. map方法
let numbers = [1, 2, 3, 4];// 对每个元素执行函数并返回新数组
let squares = numbers.map(num => num * num);
console.log(squares); // [1, 4, 9, 16]// 处理对象数组
let users = [{name: 'John', age: 25},{name: 'Jane', age: 30}
];
let names = users.map(user => user.name);
console.log(names); // ["John", "Jane"]
7. filter方法
let numbers = [1, 2, 3, 4, 5, 6];// 过滤满足条件的元素
let evens = numbers.filter(num => num % 2 === 0);
console.log(evens); // [2, 4, 6]// 过滤对象数组
let products = [{name: 'Apple', price: 1.5},{name: 'Banana', price: 0.5},{name: 'Orange', price: 2}
];
let cheap = products.filter(product => product.price < 1);
console.log(cheap); // [{name: "Banana", price: 0.5}]
8. reduce方法
let numbers = [1, 2, 3, 4];// 累加
let sum = numbers.reduce((accumulator, current) => accumulator + current, 0);
console.log(sum); // 10// 计算最大值
let max = numbers.reduce((a, b) => Math.max(a, b));
console.log(max); // 4// 复杂示例 - 统计字母出现次数
let words = ['hello', 'world', 'javascript'];
let letterCount = words.reduce((acc, word) => {for (let letter of word) {acc[letter] = (acc[letter] || 0) + 1;}return acc;
}, {});
console.log(letterCount); // {h: 2, e: 1, l: 4, o: 3, w: 1, r: 2, d: 1, j: 1, a: 2, v: 1, s: 1, c: 1, i: 1, p: 1, t: 1}
八、【示例】奇偶数组
/*** 奇偶数组分割示例* 将一个数组分割为奇数数组和偶数数组*/function splitOddEven(arr) {// 使用filter方法筛选奇数let odd = arr.filter(num => num % 2 !== 0);// 使用filter方法筛选偶数let even = arr.filter(num => num % 2 === 0);return { odd, even };
}let numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
let result = splitOddEven(numbers);console.log('原始数组:', numbers);
console.log('奇数数组:', result.odd); // [1, 3, 5, 7, 9]
console.log('偶数数组:', result.even); // [2, 4, 6, 8, 10]
九、综合案例:地区选择器
/*** 地区选择器* 实现省市区三级联动选择功能*/// 模拟地区数据
const areaData = {'北京市': {'北京市': ['东城区', '西城区', '朝阳区', '丰台区', '石景山区', '海淀区']},'广东省': {'广州市': ['荔湾区', '越秀区', '海珠区', '天河区', '白云区'],'深圳市': ['罗湖区', '福田区', '南山区', '宝安区', '龙岗区']},'浙江省': {'杭州市': ['上城区', '下城区', '江干区', '拱墅区', '西湖区'],'宁波市': ['海曙区', '江北区', '北仑区', '镇海区', '鄞州区']}
};// 获取DOM元素
const provinceSelect = document.getElementById('province');
const citySelect = document.getElementById('city');
const districtSelect = document.getElementById('district');/*** 初始化省份选择框*/
function initProvince() {// 获取所有省份const provinces = Object.keys(areaData);// 清空并添加默认选项provinceSelect.innerHTML = '<option value="">请选择省份</option>';// 添加省份选项provinces.forEach(province => {const option = document.createElement('option');option.value = province;option.textContent = province;provinceSelect.appendChild(option);});// 添加事件监听provinceSelect.addEventListener('change', updateCities);
}/*** 更新城市选择框*/
function updateCities() {// 获取选中的省份const province = provinceSelect.value;// 清空并添加默认选项citySelect.innerHTML = '<option value="">请选择城市</option>';districtSelect.innerHTML = '<option value="">请选择区县</option>';if (!province) return;// 获取该省份下的城市const cities = Object.keys(areaData[province]);// 添加城市选项cities.forEach(city => {const option = document.createElement('option');option.value = city;option.textContent = city;citySelect.appendChild(option);});// 添加事件监听citySelect.addEventListener('change', updateDistricts);
}/*** 更新区县选择框*/
function updateDistricts() {// 获取选中的省份和城市const province = provinceSelect.value;const city = citySelect.value;// 清空并添加默认选项districtSelect.innerHTML = '<option value="">请选择区县</option>';if (!province || !city) return;// 获取该城市下的区县const districts = areaData[province][city];// 添加区县选项districts.forEach(district => {const option = document.createElement('option');option.value = district;option.textContent = district;districtSelect.appendChild(option);});
}// 页面加载完成后初始化
document.addEventListener('DOMContentLoaded', initProvince);// HTML结构示例(实际使用时需要添加到页面中):
/*
<div><select id="province"><option value="">请选择省份</option></select><select id="city"><option value="">请选择城市</option></select><select id="district"><option value="">请选择区县</option></select>
</div>
*/
十、其他实用数组方法
1. some / every
let numbers = [1, 2, 3, 4, 5];// some - 检查是否有元素满足条件
let hasEven = numbers.some(num => num % 2 === 0);
console.log(hasEven); // true// every - 检查所有元素是否都满足条件
let allPositive = numbers.every(num => num > 0);
console.log(allPositive); // true
2. flat / flatMap
let nestedArray = [1, [2, 3], [4, [5, 6]]];// flat - 扁平化数组
console.log(nestedArray.flat()); // [1, 2, 3, 4, [5, 6]]
console.log(nestedArray.flat(2)); // [1, 2, 3, 4, 5, 6]// flatMap - 先映射后扁平化
let phrases = ["hello world", "the quick brown fox"];
let words = phrases.flatMap(phrase => phrase.split(" "));
console.log(words); // ["hello", "world", "the", "quick", "brown", "fox"]
3. fill方法
// 创建一个长度为5的数组并用0填充
let zeros = new Array(5).fill(0);
console.log(zeros); // [0, 0, 0, 0, 0]// 填充部分元素
let numbers = [1, 2, 3, 4, 5];
numbers.fill(0, 1, 3); // 从索引1到3(不包括3)填充0
console.log(numbers); // [1, 0, 0, 4, 5]
4. Array.from
// 从类数组对象创建数组
let arrayLike = {0: 'a', 1: 'b', 2: 'c', length: 3};
let arr = Array.from(arrayLike);
console.log(arr); // ["a", "b", "c"]// 从可迭代对象创建数组
let set = new Set(['x', 'y', 'z']);
let arrFromSet = Array.from(set);
console.log(arrFromSet); // ["x", "y", "z"]// 带映射函数的Array.from
let squares = Array.from([1, 2, 3], x => x * x);
console.log(squares); // [1, 4, 9]
以上内容涵盖了JavaScript数组的主要知识点和实用案例,包括数组的定义、操作、遍历、排序和各种常用方法,以及两个综合案例。这些知识点是JavaScript开发中非常基础和重要的部分。
案例代码
案例1:购物车功能实现
/*** 购物车功能实现* 包含添加商品、删除商品、计算总价、清空购物车等功能*/class ShoppingCart {constructor() {this.items = []; // 存储购物车商品}// 添加商品addItem(product, quantity = 1) {// 检查商品是否已存在const existingItem = this.items.find(item => item.id === product.id);if (existingItem) {// 商品已存在,增加数量existingItem.quantity += quantity;} else {// 商品不存在,添加新商品this.items.push({id: product.id,name: product.name,price: product.price,quantity: quantity});}console.log(`已添加 ${quantity} 件 ${product.name} 到购物车`);}// 删除商品removeItem(productId, quantity = 1) {const itemIndex = this.items.findIndex(item => item.id === productId);if (itemIndex === -1) {console.log('购物车中未找到该商品');return;}const item = this.items[itemIndex];if (item.quantity <= quantity) {// 删除整个商品项this.items.splice(itemIndex, 1);console.log(`已从购物车移除 ${item.name}`);} else {// 减少商品数量item.quantity -= quantity;console.log(`已从购物车减少 ${quantity} 件 ${item.name}`);}}// 计算总价calculateTotal() {return this.items.reduce((total, item) => {return total + (item.price * item.quantity);}, 0).toFixed(2);}// 清空购物车clearCart() {this.items = [];console.log('购物车已清空');}// 显示购物车内容displayCart() {console.log('购物车内容:');this.items.forEach(item => {console.log(`${item.name} x ${item.quantity} - ¥${(item.price * item.quantity).toFixed(2)}`);});console.log(`总计: ¥${this.calculateTotal()}`);}
}// 使用示例
const cart = new ShoppingCart();// 商品数据
const products = [{ id: 1, name: 'iPhone 13', price: 5999 },{ id: 2, name: 'AirPods Pro', price: 1499 },{ id: 3, name: 'MacBook Pro', price: 12999 }
];// 添加商品
cart.addItem(products[0]); // 添加1件iPhone
cart.addItem(products[1], 2); // 添加2件AirPods
cart.addItem(products[0]); // 再次添加iPhone// 显示购物车
cart.displayCart();// 删除商品
cart.removeItem(1); // 移除1件iPhone
cart.removeItem(2, 1); // 移除1件AirPods// 显示更新后的购物车
cart.displayCart();// 清空购物车
cart.clearCart();
cart.displayCart();
案例2:任务管理系统
/*** 任务管理系统* 包含添加任务、完成任务、删除任务、筛选任务等功能*/class TaskManager {constructor() {this.tasks = []; // 存储所有任务this.filters = {status: 'all', // all, active, completedpriority: 'all' // all, high, medium, low};}// 添加任务addTask(title, priority = 'medium') {const newTask = {id: Date.now(), // 使用时间戳作为唯一IDtitle,priority,completed: false,createdAt: new Date()};this.tasks.push(newTask);console.log(`任务 "${title}" 已添加`);this.displayTasks();}// 完成任务completeTask(taskId) {const task = this.tasks.find(t => t.id === taskId);if (task) {task.completed = true;console.log(`任务 "${task.title}" 已完成`);this.displayTasks();} else {console.log('未找到该任务');}}// 删除任务deleteTask(taskId) {const index = this.tasks.findIndex(t => t.id === taskId);if (index !== -1) {const deletedTask = this.tasks.splice(index, 1)[0];console.log(`任务 "${deletedTask.title}" 已删除`);this.displayTasks();} else {console.log('未找到该任务');}}// 设置筛选条件setFilter(type, value) {if (this.filters.hasOwnProperty(type)) {this.filters[type] = value;console.log(`筛选条件已更新: ${type}=${value}`);this.displayTasks();} else {console.log('无效的筛选类型');}}// 获取筛选后的任务getFilteredTasks() {return this.tasks.filter(task => {// 状态筛选const statusMatch = this.filters.status === 'all' ||(this.filters.status === 'active' && !task.completed) ||(this.filters.status === 'completed' && task.completed);// 优先级筛选const priorityMatch = this.filters.priority === 'all' || task.priority === this.filters.priority;return statusMatch && priorityMatch;});}// 显示任务displayTasks() {const filteredTasks = this.getFilteredTasks();console.log('\n当前任务列表:');console.log(`状态: ${this.filters.status} | 优先级: ${this.filters.priority}`);console.log('--------------------------------');if (filteredTasks.length === 0) {console.log('没有任务');return;}filteredTasks.forEach(task => {const status = task.completed ? '✓' : ' ';const priorityColors = {high: '\x1b[31m', // 红色medium: '\x1b[33m', // 黄色low: '\x1b[32m' // 绿色};const priorityText = `${priorityColors[task.priority]}${task.priority}\x1b[0m`;console.log(`[${status}] ${task.id} - ${task.title} (优先级: ${priorityText})`);});console.log(`共 ${filteredTasks.length} 个任务\n`);}
}// 使用示例
const taskManager = new TaskManager();// 添加任务
taskManager.addTask('学习JavaScript数组', 'high');
taskManager.addTask('写项目文档', 'medium');
taskManager.addTask('买咖啡', 'low');// 完成任务
taskManager.completeTask(taskManager.tasks[0].id);// 设置筛选条件
taskManager.setFilter('status', 'active');
taskManager.setFilter('priority', 'high');// 删除任务
taskManager.deleteTask(taskManager.tasks[1].id);// 重置筛选
taskManager.setFilter('status', 'all');
taskManager.setFilter('priority', 'all');
案例3:数据分析仪表板
/*** 数据分析仪表板* 对数据集进行各种统计和分析*/class DataDashboard {constructor(data) {this.data = data;}// 基本统计信息getBasicStats() {const count = this.data.length;const sum = this.data.reduce((acc, val) => acc + val, 0);const mean = sum / count;// 计算标准差const squaredDiffs = this.data.map(val => Math.pow(val - mean, 2));const variance = squaredDiffs.reduce((acc, val) => acc + val, 0) / count;const stdDev = Math.sqrt(variance);// 排序找中位数const sortedData = [...this.data].sort((a, b) => a - b);const median = count % 2 === 0 ? (sortedData[count/2 - 1] + sortedData[count/2]) / 2: sortedData[Math.floor(count/2)];// 最小最大值const min = Math.min(...this.data);const max = Math.max(...this.data);return {count,sum,mean: parseFloat(mean.toFixed(2)),median: parseFloat(median.toFixed(2)),stdDev: parseFloat(stdDev.toFixed(2)),min,max,range: max - min};}// 数据分组统计groupData(binSize) {const min = Math.min(...this.data);const max = Math.max(...this.data);// 计算分组数量const binCount = Math.ceil((max - min) / binSize);// 初始化分组const bins = Array(binCount).fill().map((_, i) => ({min: min + i * binSize,max: min + (i + 1) * binSize,count: 0,values: []}));// 填充数据到分组this.data.forEach(value => {// 找到合适的分组let binIndex = Math.floor((value - min) / binSize);// 处理最大值的情况binIndex = binIndex >= binCount ? binCount - 1 : binIndex;bins[binIndex].count++;bins[binIndex].values.push(value);});return bins;}// 数据过滤filterData(minValue, maxValue) {return this.data.filter(value => value >= minValue && value <= maxValue);}// 数据标准化 (0-1)normalizeData() {const min = Math.min(...this.data);const max = Math.max(...this.data);const range = max - min;return this.data.map(value => (value - min) / range);}// 显示数据分布showDistribution(binSize = 10) {const stats = this.getBasicStats();const bins = this.groupData(binSize);console.log('\n=== 数据分布分析 ===');console.log(`数据集大小: ${stats.count}`);console.log(`最小值: ${stats.min}, 最大值: ${stats.max}, 平均值: ${stats.mean}`);console.log(`中位数: ${stats.median}, 标准差: ${stats.stdDev}`);console.log('\n分组统计:');bins.forEach((bin, i) => {const percentage = ((bin.count / stats.count) * 100).toFixed(1);const bar = '■'.repeat(Math.round(percentage / 5)); // 每5%一个方块console.log(`${i + 1}. [${bin.min.toFixed(1)}-${bin.max.toFixed(1)}): ` +`${bin.count} 项 (${percentage}%) ${bar}`);});}
}// 使用示例
// 生成随机测试数据 (100个0-100之间的随机数)
const testData = Array.from({ length: 100 }, () => Math.floor(Math.random() * 100));const dashboard = new DataDashboard(testData);// 显示基本统计信息
console.log('基本统计信息:', dashboard.getBasicStats());// 显示数据分布
dashboard.showDistribution(10);// 数据过滤
const filteredData = dashboard.filterData(30, 70);
console.log('\n过滤后的数据(30-70):', filteredData.length, '项');// 数据标准化
const normalizedData = dashboard.normalizeData();
console.log('\n标准化后的前10项数据:', normalizedData.slice(0, 10).map(v => v.toFixed(2)));
案例4:图片轮播组件
/*** 图片轮播组件* 实现自动轮播、手动切换、指示器导航等功能*/class ImageSlider {constructor(containerId, images, options = {}) {this.container = document.getElementById(containerId);this.images = images;this.currentIndex = 0;this.intervalId = null;// 默认配置this.options = {interval: 3000,transition: 500,showDots: true,showArrows: true,...options};// 初始化this.init();}// 初始化轮播init() {// 创建HTML结构this.container.innerHTML = `<div class="slider-container"><div class="slider-track"></div>${this.options.showArrows ? `<button class="slider-arrow prev">❮</button><button class="slider-arrow next">❯</button>` : ''}${this.options.showDots ? '<div class="slider-dots"></div>' : ''}</div>`;this.track = this.container.querySelector('.slider-track');this.track.style.transition = `${this.options.transition}ms`;// 添加图片this.images.forEach((image, index) => {const slide = document.createElement('div');slide.className = 'slide';slide.innerHTML = `<img src="${image.url}" alt="${image.alt || ''}">`;this.track.appendChild(slide);});// 添加指示器if (this.options.showDots) {this.dotsContainer = this.container.querySelector('.slider-dots');this.images.forEach((_, index) => {const dot = document.createElement('button');dot.className = 'dot';if (index === 0) dot.classList.add('active');dot.addEventListener('click', () => this.goToSlide(index));this.dotsContainer.appendChild(dot);});}// 添加箭头事件if (this.options.showArrows) {this.prevBtn = this.container.querySelector('.prev');this.nextBtn = this.container.querySelector('.next');this.prevBtn.addEventListener('click', () => this.prevSlide());this.nextBtn.addEventListener('click', () => this.nextSlide());}// 设置初始位置this.updateSlider();// 开始自动轮播this.startAutoPlay();// 鼠标悬停暂停this.container.addEventListener('mouseenter', () => this.stopAutoPlay());this.container.addEventListener('mouseleave', () => this.startAutoPlay());}// 更新滑块位置updateSlider() {const slideWidth = this.container.offsetWidth;this.track.style.transform = `translateX(-${this.currentIndex * slideWidth}px)`;// 更新指示器状态if (this.options.showDots) {const dots = this.dotsContainer.querySelectorAll('.dot');dots.forEach((dot, index) => {dot.classList.toggle('active', index === this.currentIndex);});}}// 下一张nextSlide() {this.currentIndex = (this.currentIndex + 1) % this.images.length;this.updateSlider();}// 上一张prevSlide() {this.currentIndex = (this.currentIndex - 1 + this.images.length) % this.images.length;this.updateSlider();}// 跳转到指定幻灯片goToSlide(index) {this.currentIndex = index;this.updateSlider();}// 开始自动播放startAutoPlay() {if (this.intervalId) return;this.intervalId = setInterval(() => {this.nextSlide();}, this.options.interval);}// 停止自动播放stopAutoPlay() {if (this.intervalId) {clearInterval(this.intervalId);this.intervalId = null;}}// 响应窗口大小变化handleResize() {this.updateSlider();}
}// 使用示例
document.addEventListener('DOMContentLoaded', () => {const images = [{ url: 'https://via.placeholder.com/800x400?text=Slide+1', alt: 'Slide 1' },{ url: 'https://via.placeholder.com/800x400?text=Slide+2', alt: 'Slide 2' },{ url: 'https://via.placeholder.com/800x400?text=Slide+3', alt: 'Slide 3' },{ url: 'https://via.placeholder.com/800x400?text=Slide+4', alt: 'Slide 4' }];const slider = new ImageSlider('slider-container', images, {interval: 2000,transition: 600,showDots: true,showArrows: true});// 响应窗口大小变化window.addEventListener('resize', () => slider.handleResize());
});// 对应的HTML结构:
/*
<div id="slider-container" style="width: 800px; height: 400px; overflow: hidden; position: relative;"></div><style>.slider-container {position: relative;width: 100%;height: 100%;}.slider-track {display: flex;height: 100%;}.slide {min-width: 100%;height: 100%;}.slide img {width: 100%;height: 100%;object-fit: cover;}.slider-arrow {position: absolute;top: 50%;transform: translateY(-50%);background: rgba(0,0,0,0.5);color: white;border: none;padding: 10px 15px;cursor: pointer;font-size: 18px;z-index: 10;}.prev {left: 10px;}.next {right: 10px;}.slider-dots {position: absolute;bottom: 20px;left: 50%;transform: translateX(-50%);display: flex;gap: 10px;}.dot {width: 12px;height: 12px;border-radius: 50%;background: rgba(255,255,255,0.5);border: none;cursor: pointer;padding: 0;}.dot.active {background: white;}
</style>
*/
案例5:表格排序与筛选
/*** 表格排序与筛选组件* 实现表格数据的多列排序、筛选和分页功能*/class TableManager {constructor(tableId, data, options = {}) {this.table = document.getElementById(tableId);this.originalData = data;this.currentData = [...data];this.sortState = {}; // 存储各列排序状态this.currentPage = 1;// 默认配置this.options = {pageSize: 10,sortable: true,filterable: true,pagination: true,...options};// 初始化this.initTable();this.renderTable();if (this.options.pagination) {this.renderPagination();}}// 初始化表格结构initTable() {// 清空表格this.table.innerHTML = '';// 创建表头const thead = document.createElement('thead');const headerRow = document.createElement('tr');// 获取列配置或从数据第一项推断const columns = this.options.columns || Object.keys(this.originalData[0] || {}).map(key => ({key,title: key.charAt(0).toUpperCase() + key.slice(1),sortable: true,filterable: true}));this.columns = columns;// 添加表头单元格columns.forEach(column => {const th = document.createElement('th');th.textContent = column.title;if (this.options.sortable && column.sortable !== false) {th.style.cursor = 'pointer';th.addEventListener('click', () => this.sortData(column.key));// 初始化排序状态this.sortState[column.key] = 0; // 0: 未排序, 1: 升序, -1: 降序}headerRow.appendChild(th);});thead.appendChild(headerRow);this.table.appendChild(thead);// 创建表体this.tbody = document.createElement('tbody');this.table.appendChild(this.tbody);// 添加筛选行if (this.options.filterable) {const filterRow = document.createElement('tr');filterRow.className = 'filter-row';columns.forEach(column => {const td = document.createElement('td');if (column.filterable !== false) {const input = document.createElement('input');input.type = 'text';input.placeholder = `筛选 ${column.title}`;input.addEventListener('input', (e) => {this.filterData(column.key, e.target.value);});td.appendChild(input);}filterRow.appendChild(td);});thead.appendChild(filterRow);}}// 渲染表格数据renderTable() {// 清空表体this.tbody.innerHTML = '';// 计算分页数据const start = (this.currentPage - 1) * this.options.pageSize;const end = start + this.options.pageSize;const pageData = this.currentData.slice(start, end);// 添加数据行pageData.forEach(row => {const tr = document.createElement('tr');this.columns.forEach(column => {const td = document.createElement('td');td.textContent = row[column.key];tr.appendChild(td);});this.tbody.appendChild(tr);});// 如果没有数据,显示空行if (pageData.length === 0) {const tr = document.createElement('tr');const td = document.createElement('td');td.colSpan = this.columns.length;td.textContent = '没有数据';tr.appendChild(td);this.tbody.appendChild(tr);}}// 渲染分页控件renderPagination() {// 移除旧的分页控件const oldPagination = this.table.nextElementSibling;if (oldPagination && oldPagination.classList.contains('pagination')) {oldPagination.remove();}const totalPages = Math.ceil(this.currentData.length / this.options.pageSize);// 如果不需要分页或只有一页,则不显示分页控件if (totalPages <= 1) return;const pagination = document.createElement('div');pagination.className = 'pagination';// 上一页按钮const prevBtn = document.createElement('button');prevBtn.textContent = '上一页';prevBtn.disabled = this.currentPage === 1;prevBtn.addEventListener('click', () => {this.currentPage--;this.renderTable();this.renderPagination();});pagination.appendChild(prevBtn);// 页码按钮const maxVisiblePages = 5;let startPage = Math.max(1, this.currentPage - Math.floor(maxVisiblePages / 2));let endPage = Math.min(totalPages, startPage + maxVisiblePages - 1);// 调整起始页码,确保显示maxVisiblePages个页码if (endPage - startPage + 1 < maxVisiblePages) {startPage = Math.max(1, endPage - maxVisiblePages + 1);}// 第一页if (startPage > 1) {const firstPageBtn = document.createElement('button');firstPageBtn.textContent = '1';firstPageBtn.addEventListener('click', () => {this.currentPage = 1;this.renderTable();this.renderPagination();});pagination.appendChild(firstPageBtn);if (startPage > 2) {const ellipsis = document.createElement('span');ellipsis.textContent = '...';pagination.appendChild(ellipsis);}}// 中间页码for (let i = startPage; i <= endPage; i++) {const pageBtn = document.createElement('button');pageBtn.textContent = i;pageBtn.className = i === this.currentPage ? 'active' : '';pageBtn.addEventListener('click', () => {this.currentPage = i;this.renderTable();this.renderPagination();});pagination.appendChild(pageBtn);}// 最后一页if (endPage < totalPages) {if (endPage < totalPages - 1) {const ellipsis = document.createElement('span');ellipsis.textContent = '...';pagination.appendChild(ellipsis);}const lastPageBtn = document.createElement('button');lastPageBtn.textContent = totalPages;lastPageBtn.addEventListener('click', () => {this.currentPage = totalPages;this.renderTable();this.renderPagination();});pagination.appendChild(lastPageBtn);}// 下一页按钮const nextBtn = document.createElement('button');nextBtn.textContent = '下一页';nextBtn.disabled = this.currentPage === totalPages;nextBtn.addEventListener('click', () => {this.currentPage++;this.renderTable();this.renderPagination();});pagination.appendChild(nextBtn);// 添加到表格后面this.table.insertAdjacentElement('afterend', pagination);}// 排序数据sortData(columnKey) {// 切换排序状态: 无排序 -> 升序 -> 降序 -> 无排序this.sortState[columnKey] = ((this.sortState[columnKey] || 0) + 2) % 3 - 1;// 重置其他列的排序状态Object.keys(this.sortState).forEach(key => {if (key !== columnKey) {this.sortState[key] = 0;}});if (this.sortState[columnKey] === 0) {// 无排序,恢复原始顺序this.currentData = [...this.originalData];} else {// 排序数据const sortOrder = this.sortState[columnKey];this.currentData.sort((a, b) => {// 处理可能的undefined或null值const valA = a[columnKey] !== undefined ? a[columnKey] : '';const valB = b[columnKey] !== undefined ? b[columnKey] : '';// 数字和字符串比较if (typeof valA === 'number' && typeof valB === 'number') {return (valA - valB) * sortOrder;}return valA.toString().localeCompare(valB.toString()) * sortOrder;});}// 重置到第一页this.currentPage = 1;// 重新渲染this.renderTable();this.renderPagination();// 更新表头排序指示器this.updateSortIndicators();}// 更新表头排序指示器updateSortIndicators() {const headers = this.table.querySelectorAll('th');headers.forEach((header, index) => {const columnKey = this.columns[index].key;header.textContent = this.columns[index].title;if (this.sortState[columnKey] === 1) {header.textContent += ' ↑';} else if (this.sortState[columnKey] === -1) {header.textContent += ' ↓';}});}// 筛选数据filterData(columnKey, searchText) {// 重置排序状态this.sortState = {};this.updateSortIndicators();// 重置到第一页this.currentPage = 1;if (!searchText) {// 没有筛选文本,恢复原始数据this.currentData = [...this.originalData];} else {// 应用筛选const searchLower = searchText.toLowerCase();this.currentData = this.originalData.filter(item => {const value = item[columnKey] !== undefined ? item[columnKey] : '';return value.toString().toLowerCase().includes(searchLower);});}// 重新渲染this.renderTable();this.renderPagination();}
}// 使用示例
document.addEventListener('DOMContentLoaded', () => {// 示例数据const employeeData = [{ id: 1, name: '张三', department: '研发部', salary: 12000, joinDate: '2020-05-15' },{ id: 2, name: '李四', department: '市场部', salary: 8500, joinDate: '2019-11-03' },{ id: 3, name: '王五', department: '研发部', salary: 15000, joinDate: '2018-07-22' },{ id: 4, name: '赵六', department: '人事部', salary: 7500, joinDate: '2021-02-18' },{ id: 5, name: '钱七', department: '市场部', salary: 9200, joinDate: '2020-09-30' },{ id: 6, name: '孙八', department: '研发部', salary: 11000, joinDate: '2019-04-12' },{ id: 7, name: '周九', department: '财务部', salary: 13000, joinDate: '2017-12-05' },{ id: 8, name: '吴十', department: '人事部', salary: 6800, joinDate: '2022-01-20' },{ id: 9, name: '郑十一', department: '研发部', salary: 14000, joinDate: '2018-10-15' },{ id: 10, name: '王十二', department: '市场部', salary: 8800, joinDate: '2020-07-08' },{ id: 11, name: '李十三', department: '财务部', salary: 12500, joinDate: '2019-08-25' },{ id: 12, name: '张十四', department: '研发部', salary: 11500, joinDate: '2021-05-14' }];// 初始化表格const tableManager = new TableManager('employee-table', employeeData, {pageSize: 5,columns: [{ key: 'id', title: 'ID', sortable: true, filterable: false },{ key: 'name', title: '姓名', sortable: true, filterable: true },{ key: 'department', title: '部门', sortable: true, filterable: true },{ key: 'salary', title: '薪资', sortable: true, filterable: false },{ key: 'joinDate', title: '入职日期', sortable: true, filterable: false }]});
});// 对应的HTML结构:
/*
<table id="employee-table"></table><style>#employee-table {width: 100%;border-collapse: collapse;margin-bottom: 20px;}#employee-table th, #employee-table td {border: 1px solid #ddd;padding: 8px 12px;text-align: left;}#employee-table th {background-color: #f2f2f2;cursor: pointer;}#employee-table th:hover {background-color: #e6e6e6;}#employee-table tr:nth-child(even) {background-color: #f9f9f9;}#employee-table tr:hover {background-color: #f1f1f1;}.filter-row input {width: 100%;padding: 5px;box-sizing: border-box;}.pagination {display: flex;gap: 5px;margin-top: 10px;}.pagination button {padding: 5px 10px;cursor: pointer;}.pagination button.active {background-color: #4CAF50;color: white;border: none;}.pagination button:disabled {opacity: 0.5;cursor: not-allowed;}.pagination span {padding: 5px 10px;}
</style>
*/
这些案例涵盖了JavaScript数组在实际开发中的多种应用场景,包括:
- 购物车功能 - 展示数组的增删改查和计算操作
- 任务管理系统 - 展示数组的筛选、排序和状态管理
- 数据分析仪表板 - 展示数组的统计和分组操作
- 图片轮播组件 - 展示数组在UI组件中的应用
- 表格排序与筛选 - 展示复杂的数据处理和交互