JavaScript 代理模式与发布订阅模式实战解析

作者:闭包旅人

时间:2026-10-23

浏览:437

本文深入解析JavaScript中的代理模式与发布订阅模式。通过虚拟代理实现图片预加载,利用缓存代理优化重复计算性能,并基于数组操作实现发布订阅机制。文章提供完整代码示例与运行结果,帮助开发者理解核心原理及实际应用。

文章目录

JavaScript代理模式与发布订阅模式实战解析

本文通过具体实例详细讲解JavaScript中的代理模式与发布订阅模式,旨在为读者提供参考并辅助学习。

将这两种设计模式合并在同一篇文章中讨论,主要是为了保持内容的连贯性与篇幅的完整性。

撰写技术博客的首要目标在于梳理个人知识体系,通过用自己的语言重新阐述概念,将外部知识内化为个人能力。

本文为设计模式系列的第二篇内容,第一篇内容可参考相关历史文章。

代理模式:虚拟与缓存实现

1,代理模式,仅学习了虚拟代理以及缓存代理,具体案例

1)虚拟代理应用场景解析


//业务代码
var myImage = (function() {
    var imgNode = document.createElement("img");
    document.body.appendChild(imgNode);
    return {
      setSrc: function(src) {
        console.log(1111);
        imgNode.src = src;
      }
    }
})();
// 设计模式代码
var ProxyImage = (function() {
    var img = new Image();
    //这个img只是用来判断图片是否加载完成,加载完成之后修改图片链接
    img.onload = function() {
      console.log(this);
      myImage.setSrc(this.src);
    };
    return {
      setSrc: function(src) {
        console.log(22);
        myImage.setSrc("http://img.lanrentuku.com/img/allimg/1212/5-121204193Q9-50.gif");
        img.src = src;
      }
    }
})();

该示例借鉴了经典实现思路。核心业务逻辑是将图片DOM节点插入文档树,而代理模式则通过创建一个隐藏的Image对象来监听加载状态(onload)。当图片加载完成后,代理对象将替换原始图片的链接,从而优化用户体验。

2)缓存代理实现示例


<script>
//缓存代理
// 计算乘法
var mult = function() {
    var a = 1;
    for (var i = 0, ilen = arguments.length; i < ilen; i += 1) {
      a = a * arguments[i];
    }
    return a;
};
// 代理函数
var proxyFunc = function(fn) {
    var cache = {}; // 缓存对象
    return function() {
      //利用闭包
      var args = Array.prototype.join.call(arguments);
      if (args in cache) {
        return cache[args]; // 使用缓存代理
      }
      return cache[args] = fn.apply(this, arguments);
    }
};
var proxyMult = proxyFunc(mult);
console.log(proxyMult(1, 2, 3, 4)); // 24
console.log(proxyMult(1, 2, 3, 4)); // 缓存取 24
</script>

代码运行后的输出结果如下所示。

JavaScript代理模式与发布订阅模式实战解析

该方案利用闭包特性,将计算结果存储在缓存对象中,从而避免重复执行昂贵的计算过程。

发布订阅模式核心机制

2,订阅发布模式(Pub/Sub)


<script>
var Event = (function(){
  var list = {},
     listen,
     trigger,
     remove;
     //添加订阅对象
     listen = function(key,fn){
      if(!list[key]) {
        list[key] = [];
      }
      list[key].push(fn);
    };
    //触发订阅内容
    trigger = function(){
      var key = Array.prototype.shift.call(arguments),
         fns = list[key];
      if(!fns || fns.length === 0) {
        return false;
      }
      for(var i = 0, fn; fn = fns[i++];) {
        fn.apply(this,arguments);
      }
    };
    //删除订阅内容
    remove = function(key,fn){
      var fns = list[key];
      if(!fns) {
        return false;
      }
      if(!fn) {
        fns && (fns.length = 0);
      }else {
        for(var i = fns.length - 1; i >= 0; i--){
          var _fn = fns[i];
          if(_fn === fn) {
            fns.splice(i,1);
          }
        }
      }
    };
    return {
      listen: listen,
      trigger: trigger,
      remove: remove
    }
})();
// 测试代码如下:
Event.listen("color",function(size) {
  console.log("尺码为:"+size); // 打印出尺码为42
});
Event.trigger("color",42);
</script>

该模式的运行结果展示如下。

JavaScript代理模式与发布订阅模式实战解析

从本质上看,发布订阅模式是对数组进行增删改查操作的封装。其核心逻辑在于维护一个事件列表,实现事件的注册与触发。

本文内容到此结束。

感兴趣的用户可以使用在线HTML/CSS/JavaScript前端代码调试运行工具:http://tools.jb51.net/code/WebCodeRun 来测试上述代码的实际运行效果。

如需了解更多JavaScript相关知识,建议查阅本站系列教程,包括《javascript面向对象入门教程》、《JavaScript错误与调试技巧总结》、《JavaScript数据结构与算法技巧总结》、《JavaScript遍历算法与技巧总结》及《JavaScript数学运算用法总结》。

希望本文关于JavaScript程序设计的阐述能对大家的技术实践有所帮助。

实用工具推荐

电子包浆

绿化、压缩、噪点和虚拟水印,自由调节做旧程度。

使用 ›
图片压缩

选择画质和输出格式,预览压缩前后的大小。

使用 ›
相关文章