JavaScript高级实战:现代前端开发必备的10个核心技术
一、ES6+核心特性实战
1. 解构赋值的妙用
// 对象解构
const user = { name: '张三', age: 28, email: 'zhangsan@example.com' };
const { name, ...rest } = user;
console.log(name); // "张三"
console.log(rest); // { age: 28, email: 'zhangsan@example.com' }
// 数组解构
const [first, , third] = ['a', 'b', 'c'];
console.log(first, third); // "a" "c"
// 函数参数解构
function getUserInfo({ id, name = '匿名' }) {
return `ID: ${id}, 姓名: ${name}`;
}
console.log(getUserInfo({ id: 1 })); // "ID: 1, 姓名: 匿名"
2. Promise高级应用
// 创建可取消的Promise
function makeCancelable(promise) {
let hasCanceled = false;
const wrappedPromise = new Promise((resolve, reject) => {
promise.then(
val => hasCanceled ? reject({ isCanceled: true }) : resolve(val),
error => hasCanceled ? reject({ isCanceled: true }) : reject(error)
);
});
return {
promise: wrappedPromise,
cancel() {
hasCanceled = true;
}
};
}
// 使用示例
const cancelable = makeCancelable(fetch('/api/data'));
cancelable.promise
.then(data => console.log(data))
.catch(err => {
if (err.isCanceled) {
console.log('请求已取消');
} else {
console.error('请求失败', err);
}
});
// 取消请求
cancelable.cancel();
1. 观察者模式实现
class EventEmitter {
constructor() {
this.events = {};
}
on(event, listener) {
if (!this.events[event]) {
this.events[event] = [];
}
this.events[event].push(listener);
return this;
}
off(event, listener) {
if (!this.events[event]) return;
const index = this.events[event].indexOf(listener);
if (index > -1) {
this.events[event].splice(index, 1);
}
return this;
}
emit(event, ...args) {
if (!this.events[event]) return;
this.events[event].forEach(listener => {
listener.apply(this, args);
});
return this;
}
once(event, listener) {
const onceListener = (...args) => {
this.off(event, onceListener);
listener.apply(this, args);
};
return this.on(event, onceListener);
}
}
// 使用示例
const emitter = new EventEmitter();
emitter.on('data', data => console.log('收到数据:', data));
emitter.emit('data', { id: 1, name: '测试' });
2. 策略模式应用
const validationStrategies = {
isNonEmpty(value, errorMsg) {
if (value === '') return errorMsg;
},
minLength(value, length, errorMsg) {
if (value.length {
const strategy = rule.strategy.split(':');
const errorMsg = rule.errorMsg;
this.cache.push(() => {
const strategyName = strategy.shift();
strategy.unshift(value);
strategy.push(errorMsg);
return validationStrategies[strategyName].apply(null, strategy);
});
});
}
validate() {
for (let i = 0, len = this.cache.length; i < len; i++) {
const errorMsg = this.cache[i]();
if (errorMsg) return errorMsg;
}
}
}
// 使用示例
const validator = new Validator();
validator.add('13812345678', [{
strategy: 'isMobile',
errorMsg: '手机号格式不正确'
}]);
validator.add('abc', [{
strategy: 'minLength:6',
errorMsg: '密码长度不能少于6位'
}]);
console.log(validator.validate()); // "密码长度不能少于6位"
1. 虚拟列表实现
class VirtualList {
constructor(container, itemHeight, totalItems, renderItem) {
this.container = container;
this.itemHeight = itemHeight;
this.totalItems = totalItems;
this.renderItem = renderItem;
this.visibleItems = Math.ceil(container.clientHeight / itemHeight);
this.startIndex = 0;
this.endIndex = this.startIndex + this.visibleItems;
this.content = document.createElement('div');
this.content.style.height = `${totalItems * itemHeight}px`;
container.appendChild(this.content);
this.render();
container.addEventListener('scroll', () => this.handleScroll());
}
handleScroll() {
const scrollTop = this.container.scrollTop;
const newStartIndex = Math.floor(scrollTop / this.itemHeight);
const newEndIndex = newStartIndex + this.visibleItems;
if (newStartIndex !== this.startIndex || newEndIndex !== this.endIndex) {
this.startIndex = newStartIndex;
this.endIndex = newEndIndex;
this.render();
}
}
render() {
// 创建文档片段减少DOM操作
const fragment = document.createDocumentFragment();
for (let i = this.startIndex; i = this.totalItems) break;
const item = document.createElement('div');
item.style.position = 'absolute';
item.style.top = `${i * this.itemHeight}px`;
item.style.height = `${this.itemHeight}px`;
item.style.width = '100%';
this.renderItem(item, i);
fragment.appendChild(item);
}
this.content.innerHTML = '';
this.content.appendChild(fragment);
}
}
// 使用示例
const container = document.getElementById('list-container');
const virtualList = new VirtualList(
container,
50, // 每项高度
1000, // 总项数
(itemElement, index) => {
itemElement.textContent = `第 ${index + 1} 项`;
}
);
// main.js
const worker = new Worker('worker.js');
// 发送数据给Worker
worker.postMessage({ type: 'CALCULATE', data: largeDataSet });
// 接收Worker返回的结果
worker.onmessage = function(event) {
console.log('收到计算结果:', event.data);
};
// worker.js
self.onmessage = function(event) {
if (event.data.type === 'CALCULATE') {
const result = heavyCalculation(event.data.data);
self.postMessage(result);
}
};
function heavyCalculation(data) {
// 执行耗时计算
return data.map(item => {
// 复杂计算逻辑...
return processedItem;
});
}
四、现代JavaScript API应用
1. Intersection Observer实现懒加载
// 图片懒加载
document.addEventListener('DOMContentLoaded', () => {
const lazyImages = document.querySelectorAll('img[data-src]');
const observer = new IntersectionObserver((entries, observer) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
const img = entry.target;
img.src = img.dataset.src;
img.onload = () => {
img.removeAttribute('data-src');
};
observer.unobserve(img);
}
});
}, {
rootMargin: '200px 0px' // 提前200px加载
});
lazyImages.forEach(img => observer.observe(img));
});
// 无限滚动
const infiniteScrollObserver = new IntersectionObserver((entries) => {
if (entries[0].isIntersecting) {
loadMoreContent();
}
}, { threshold: 0.1 });
infiniteScrollObserver.observe(document.querySelector('.load-more-trigger'));
2. Proxy实现数据响应式
function reactive(target) {
const handler = {
get(target, key, receiver) {
track(target, key);
if (typeof target[key] === 'object' && target[key] !== null) {
return reactive(target[key]);
}
return Reflect.get(target, key, receiver);
},
set(target, key, value, receiver) {
const oldValue = target[key];
const result = Reflect.set(target, key, value, receiver);
if (oldValue !== value) {
trigger(target, key);
}
return result;
}
};
return new Proxy(target, handler);
}
// 简单的依赖收集和触发
const targetMap = new WeakMap();
let activeEffect = null;
function track(target, key) {
if (activeEffect) {
let depsMap = targetMap.get(target);
if (!depsMap) {
targetMap.set(target, (depsMap = new Map()));
}
let dep = depsMap.get(key);
if (!dep) {
depsMap.set(key, (dep = new Set()));
}
dep.add(activeEffect);
}
}
function trigger(target, key) {
const depsMap = targetMap.get(target);
if (!depsMap) return;
const dep = depsMap.get(key);
if (dep) {
dep.forEach(effect => effect());
}
}
// 使用示例
const state = reactive({ count: 0, user: { name: '张三' } });
function effect(fn) {
activeEffect = fn;
fn();
activeEffect = null;
}
effect(() => {
console.log(`count值变为: ${state.count}`);
});
state.count++; // 控制台输出: "count值变为: 1"
state.user.name = '李四'; // 不会触发effect,因为只追踪了count
