JavaScript案例0322

以下是一些涵盖不同高级JavaScript概念和应用的案例,每个案例都有详细解释:


案例1:实现 Promise/A+ 规范的手写 Promise

javascript 复制代码
class MyPromise {
  constructor(executor) {
    this.state = 'pending';
    this.value = undefined;
    this.reason = undefined;
    this.onFulfilledCallbacks = [];
    this.onRejectedCallbacks = [];

    const resolve = (value) => {
      if (this.state === 'pending') {
        this.state = 'fulfilled';
        this.value = value;
        this.onFulfilledCallbacks.forEach(fn => fn());
      }
    };

    const reject = (reason) => {
      if (this.state === 'pending') {
        this.state = 'rejected';
        this.reason = reason;
        this.onRejectedCallbacks.forEach(fn => fn());
      }
    };

    try {
      executor(resolve, reject);
    } catch (err) {
      reject(err);
    }
  }

  then(onFulfilled, onRejected) {
    const promise2 = new MyPromise((resolve, reject) => {
      const microtask = (fn, value) => {
        queueMicrotask(() => {
          try {
            const x = fn(value);
            resolvePromise(promise2, x, resolve, reject);
          } catch (e) {
            reject(e);
          }
        });
      };

      if (this.state === 'fulfilled') {
        microtask(onFulfilled, this.value);
      } else if (this.state === 'rejected') {
        microtask(onRejected, this.reason);
      } else {
        this.onFulfilledCallbacks.push(() => microtask(onFulfilled, this.value));
        this.onRejectedCallbacks.push(() => microtask(onRejected, this.reason));
      }
    });

    return promise2;
  }
}

// 辅助函数处理不同返回值类型
function resolvePromise(promise2, x, resolve, reject) {
  // ...完整实现需要处理thenable对象和循环引用等情况
}

技术点

  • Promise状态机实现
  • 微任务队列(queueMicrotask)
  • 链式调用和值穿透
  • 递归解析处理

案例2:使用 Proxy 实现自动化表单校验

javascript 复制代码
const validator = {
  set(target, prop, value) {
    const rules = {
      username: val => val.length >= 5 && val.length <= 20,
      password: val => /^(?=.*[A-Za-z])(?=.*\d)[A-Za-z\d]{8,}$/.test(val),
      age: val => Number.isInteger(val) && val >= 18
    };

    if (!rules[prop](value)) {
      throw new Error(`Invalid ${prop} value`);
    }
    target[prop] = value;
    return true;
  }
};

const formData = new Proxy({}, validator);

// 使用示例
try {
  formData.username = 'user123'; // 有效
  formData.password = 'pass1234'; // 无效,触发错误
} catch (e) {
  console.error(e.message);
}

技术点

  • Proxy API 的应用
  • 数据劫持与校验
  • 正则表达式验证
  • 自定义错误处理

案例3:实现前端路由系统(Hash模式)

javascript 复制代码
class HashRouter {
  constructor() {
    this.routes = {};
    window.addEventListener('hashchange', this.load.bind(this));
  }

  addRoute(path, callback) {
    this.routes[path] = callback;
  }

  load() {
    const hash = window.location.hash.slice(1) || '/';
    const [path, queryString] = hash.split('?');
    const query = new URLSearchParams(queryString);

    if (this.routes[path]) {
      this.routes[path](Object.fromEntries(query.entries()));
    } else {
      this.routes['404']?.();
    }
  }

  navigate(path, query = {}) {
    const queryStr = new URLSearchParams(query).toString();
    window.location.hash = `${path}${queryStr ? `?${queryStr}` : ''}`;
  }
}

// 使用示例
const router = new HashRouter();
router.addRoute('/about', (params) => {
  console.log('About page', params);
});
router.navigate('/about', { from: 'home' });

技术点

  • Hash路由原理
  • URLSearchParams API
  • 发布-订阅模式
  • 浏览器历史管理

案例4:Web Worker 多线程图像处理

javascript 复制代码
// 主线程
const worker = new Worker('image-worker.js');
const canvas = document.querySelector('canvas');
const ctx = canvas.getContext('2d');

canvas.addEventListener('change', async (e) => {
  const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
  
  worker.postMessage({
    pixels: imageData.data.buffer,
    width: canvas.width,
    height: canvas.height,
    filterType: 'grayscale'
  }, [imageData.data.buffer]);

  worker.onmessage = ({ data }) => {
    ctx.putImageData(new ImageData(new Uint8ClampedArray(data), 0, 0);
  };
});

// image-worker.js
self.addEventListener('message', ({ data }) => {
  const pixels = new Uint8ClampedArray(data.pixels);
  
  // 应用滤镜(灰度化)
  for (let i = 0; i < pixels.length; i += 4) {
    const avg = (pixels[i] + pixels[i+1] + pixels[i+2]) / 3;
    pixels[i] = avg; // R
    pixels[i+1] = avg; // G
    pixels[i+2] = avg; // B
  }
  
  self.postMessage(pixels.buffer, [pixels.buffer]);
});

技术点

  • Web Worker 多线程
  • Transferable Objects
  • Canvas 像素操作
  • 图像处理算法

案例5:实现 Observable 响应式编程

javascript 复制代码
class Observable {
  constructor(subscribe) {
    this._subscribe = subscribe;
  }

  subscribe(observer) {
    const subscription = {
      unsubscribed: false,
      unsubscribe() {
        this.unsubscribed = true;
      }
    };
    this._subscribe({
      next: val => {
        if (!subscription.unsubscribed) observer.next(val);
      },
      error: err => observer.error?.(err),
      complete: () => observer.complete?.()
    });
    return subscription;
  }

  pipe(...operators) {
    return operators.reduce((prev, fn) => fn(prev), this);
  }

  static fromEvent(element, eventName) {
    return new Observable(observer => {
      const handler = e => observer.next(e);
      element.addEventListener(eventName, handler);
      return () => element.removeEventListener(eventName, handler);
    });
  }
}

// 使用示例
const click$ = Observable.fromEvent(document, 'click')
  .pipe(
    throttle(1000),
    map(e => ({ x: e.clientX, y: e.clientY }))
  );

click$.subscribe({
  next: pos => console.log('Clicked at:', pos)
});

技术点

  • 观察者模式
  • 函数式编程
  • 操作符链式调用
  • 事件流处理

这些案例覆盖了:

  1. 异步编程核心(Promise)
  2. 元编程(Proxy)
  3. 前端架构(路由)
  4. 性能优化(Web Worker)
  5. 响应式编程(Observable)

每个案例都可以进一步扩展实现更多高级功能。例如在Promise实现中添加async/await支持,在路由系统中添加嵌套路由等。

相关推荐
三天不学习1 分钟前
Vue-Office:优雅实现Office文件预览的Vue组件
前端·javascript·vue.js·vue-office
IT199513 分钟前
uniapp笔记-swiper组件实现轮播图
前端·javascript·笔记·uni-app
Riesenzahn37 分钟前
举例说明with属性的fill-available有什么应用场景?
前端·javascript
Riesenzahn37 分钟前
websocket和socket有什么区别?
前端·javascript
渴望成为python大神的前端小菜鸟1 小时前
2025前端面试题(vue、react、uniapp、微信小程序、JS、CSS、其他)
前端·javascript·vue.js·面试·微信小程序·uni-app·react
晚风9141 小时前
Vue 3中的Teleport:超越组件边界的渲染
前端·javascript·vue.js
Cutey9161 小时前
深拷贝与浅拷贝详解(包含手写深拷贝与浅拷贝实现)
前端·javascript·面试
郡nionio1 小时前
对象数组改变其对象内容值数组没变化?
javascript·vue.js
渔樵江渚上1 小时前
Webpack 与 Vite 对比:现代前端构建工具的技术博弈
前端·javascript·面试
程序员小续1 小时前
IndexedDB + 大文件上传:离线续传的最佳实践
前端·javascript·面试