JavaScript设计模式(六):语言之魂-原型模式

简介: 语言之魂-原型模式

原型模式(Prototype)

用原型实例指向创建对象的类,使用于创建新的对象的类共享原型对象的属性以及方法。

需求:创建一个焦点轮播图

<p>自动切换</p>
<img id="carousel1" class="carousel" src=""/>
<p>监听滚动切换</p>
<img id="carousel2" class="carousel" src=""/>
// 图片轮播类
var Carousel = function (imgList, container) {
   
   
    // 轮播索引
    this.index = 0;
    // 轮播图片数组
    this.imgList = imgList;
    // 轮播图片容器     
    this.container = container;
    // 创建轮播图片
    this.create = function () {
   
   
        let img = document.getElementById(this.container);
        img.src = this.imgList[this.index];
    };
    // 切换下一张图片
    this.change = function () {
   
   
        const that = this;
        setInterval(function () {
   
   
            let img = document.getElementById(that.container);
            that.index++;
            if (that.index > that.imgList.length - 1) {
   
   
                that.index = 0;
            }
            console.log(`%c【${container}】 ---> ${that.index}`, 'background-color: pink; color: black;');
            img.src = that.imgList[that.index];
        }, 2000)
    };
};

image.png

  • 默认的轮播

      let imgList = [
          'https://dummyimage.com/500x300/f00/fff&text=00',
          'https://dummyimage.com/500x300/0f0/fff&text=01',
          'https://dummyimage.com/500x300/00f/fff&text=02',
          'https://dummyimage.com/500x300/ff0/fff&text=03',
          'https://dummyimage.com/500x300/0ff/fff&text=04',
      ];
    
      // 实例化轮播图类 - 自动切换类
      let carousel = new Carousel(imgList, 'carousel1');
      carousel.create();
      carousel.change();
    
  • 重写的轮播形式 (监听滚动切换轮播)

      // 实例化轮播图类 - 上下滑动切换类
      let SlideCarousel = function (imgList, container) {
         
         
          const that = this;
          // 构造函数继承图片轮播类
          Carousel.call(that, imgList, container);
          // 重写继承的切换下一张图片方法
          that.change = function () {
         
         
              let img = document.getElementById(that.container);
              // 监听滚动
              img.addEventListener('wheel', function (e) {
         
         
                  // 向上滚动
                  if (e.wheelDelta > 0) {
         
         
                      that.index++;
                      if (that.index > that.imgList.length - 1) {
         
         
                          that.index = 0;
                      }
                  }
                  // 向下滚动 
                  else {
         
         
                      that.index--;
                      if (that.index < 0) {
         
         
                          that.index = that.imgList.length - 1;
                      }
                  }
                  console.log(`%c【${container}】 ---> ${that.index}`, 'background-color: yellow; color: black;');
                  img.src = that.imgList[that.index];
              });
          }
      };
    
      // 实例化轮播图类 - 上下滑动切换类
      let slideCarousel = new SlideCarousel(imgList, 'carousel2');
      slideCarousel.create();
      slideCarousel.change();
    
  • 缺点:
    • 属性方法 都写在基类 Carousel 的构造函数里面,那么每次子类继承都要创建一次父类,假如父类的构造函数中创建时存在很多耗时逻辑,或者每次初始化都做一些重复性工作,这样的性能消耗很大。
      • 比如: this.create = ···this.change = ··· 就属于消耗性能的逻辑

【原型模式】优化上述代码:

  • 优化:
    • 为了提高性能,我们需要有一种 共享机制 ,这样每当创建基类时,对于每次创建的一些 简单而又差异化的属性 我们可以 放在构造函数中 ,而我们将一些 消耗资源比较大的方法 放在基类的原型 中,这样就会 避免很多不必要的消耗 ,这也就是 原型模式 的一个雏形。

image.png

  • 默认的轮播

      // 图片轮播类
      var Carousel = function (imgList, container) {
         
         
          // 轮播索引
          this.index = 0;
          // 轮播图片数组
          this.imgList = imgList;
          // 轮播图片容器     
          this.container = container;
    
      };
    
      Carousel.prototype = {
         
         
          // 创建轮播图片
          create: function () {
         
         
              let img = document.getElementById(this.container);
              img.src = this.imgList[this.index];
          },
          // 切换下一张图片
          change: function () {
         
         
              const that = this;
              setInterval(function () {
         
         
                  let img = document.getElementById(that.container);
                  that.index++;
                  if (that.index > that.imgList.length - 1) {
         
         
                      that.index = 0;
                  }
                  img.src = that.imgList[that.index];
              }, 2000)
          }
      };
    
      let imgList = [
          'https://dummyimage.com/500x300/f00/fff&text=00',
          'https://dummyimage.com/500x300/0f0/fff&text=01',
          'https://dummyimage.com/500x300/00f/fff&text=02',
          'https://dummyimage.com/500x300/ff0/fff&text=03',
          'https://dummyimage.com/500x300/0ff/fff&text=04',
      ];
    
      // 实例化轮播图类 - 自动切换类
      let carousel = new Carousel(imgList, 'carousel1');
      carousel.create();
      carousel.change();
    
  • 重写的轮播形式 (监听滚动切换轮播)

      // 实例化轮播图类 - 上下滑动切换类
      let SlideCarousel = function (imgList, container) {
         
         
          // 构造函数继承图片轮播类
          Carousel.call(this, imgList, container);
      };
    
      SlideCarousel.prototype = new Carousel();
    
      // 重写继承的切换下一张图片方法
      SlideCarousel.prototype.change = function () {
         
         
          const that = this;
          let img = document.getElementById(that.container);
          // 监听滚动
          img.addEventListener('wheel', function (e) {
         
         
              // 向上滚动
              if (e.wheelDelta > 0) {
         
         
                  that.index++;
                  if (that.index > that.imgList.length - 1) {
         
         
                      that.index = 0;
                  }
              }
              // 向下滚动 
              else {
         
         
                  that.index--;
                  if (that.index < 0) {
         
         
                      that.index = that.imgList.length - 1;
                  }
              }
              img.src = that.imgList[that.index];
          });
      };
    
      // 实例化轮播图类 - 上下滑动切换类
      let slideCarousel = new SlideCarousel(imgList, 'carousel2');
      slideCarousel.create();
      slideCarousel.change();
    

原型模式的特点:

原型模式对继承他的子类都可以访问其上的属性和方法,包括杜父类拓展的方法

// 比如:

// ···Code

// 父类上拓展的方法
Carousel.prototype.getImgListCount = function () {
   
   
    console.log(this.imgList.length);
};

// 子类上拓展的方法
SlideCarousel.prototype.getContainer = function () {
   
   
    console.log(this.container);
};

// 子类访问父类上拓展的方法
slideCarousel.getImgListCount();    // 5
// 子类访问自己类上拓展的方法
slideCarousel.getContainer();       // carousel2

原型继承

比如现在没有人的基类,只有人的一些特性类,比如游泳、跑步、唱歌、跳舞等等,那么就可以通过以下方法创造出一个人的实例

function prototypeExtend(...args) {
   
   
    // 缓存类,为实例化返回对象临时创建
    const F = function () {
   
    };
    for (let i = 0; i < args.length; i++) {
   
   
        // 遍历每个模板对象中的属性
        for (let key in args[i]) {
   
   
            // 将这些属性复制到缓存类原型中
            F.prototype[key] = args[i][key];
        }
    }
    // 返回缓存类的一个实例
    return new F();
}

let Swim = function (speed) {
   
   
    this.speed = speed;
    this.swim = function () {
   
   
        console.log('游泳速度 ' + this.speed);
    };
};

let Run = function () {
   
   
    this.run = function (speed) {
   
   
        console.log('跑步速度 ' + speed);
    };
};

let Jump = function () {
   
   
    this.jump = function () {
   
   
        console.log('跳跃动作 ');
    };
};

let person = prototypeExtend(new Swim(20), new Run(), new Jump());
person.run(10);     // 跑步速度 10
person.swim();      // 跑步速度 20
/**
 * F {
 *      [[Prototype]]: {
 *          jump: ƒ (),
 *          run: ƒ (speed),
 *          speed: 20,
 *          swim: ƒ (),
 *          constructor: ƒ ()
 *          [[Prototype]]: Object
 *      }
 * }
 */
console.log(person);
目录
相关文章
|
2月前
|
设计模式 前端开发 JavaScript
JavaScript设计模式及其在实战中的应用,涵盖单例、工厂、观察者、装饰器和策略模式
本文深入探讨了JavaScript设计模式及其在实战中的应用,涵盖单例、工厂、观察者、装饰器和策略模式,结合电商网站案例,展示了设计模式如何提升代码的可维护性、扩展性和可读性,强调了其在前端开发中的重要性。
36 2
|
2月前
|
JSON 前端开发 JavaScript
聊聊 Go 语言中的 JSON 序列化与 js 前端交互类型失真问题
在Web开发中,后端与前端的数据交换常使用JSON格式,但JavaScript的数字类型仅能安全处理-2^53到2^53间的整数,超出此范围会导致精度丢失。本文通过Go语言的`encoding/json`包,介绍如何通过将大整数以字符串形式序列化和反序列化,有效解决这一问题,确保前后端数据交换的准确性。
56 4
|
3月前
|
设计模式 JavaScript 前端开发
JavaScript设计模式--访问者模式
【10月更文挑战第1天】
40 3
|
3月前
|
XML 监控 JavaScript
JavaScript 语言对企业上网监控的技术支持
在数字化企业环境中,上网监控对企业信息安全和提升员工效率至关重要。JavaScript 作为广泛应用的脚本语言,提供了强大的技术支持,包括数据获取与分析、与服务器端交互、监控页面加载时间和网络活动,助力企业有效管理上网行为,保障信息安全。
34 6
|
4月前
|
设计模式 Java 关系型数据库
【Java笔记+踩坑】设计模式——原型模式
对比原型模式和传统方式的实现思路、代码方案、优缺点,阐述原型模式的使用场景,以及深拷贝、浅拷贝等相关概念,并扩展原型模式在Spring源码中的应用。
|
4月前
|
设计模式 Java
Java设计模式-原型模式(3)
Java设计模式-原型模式(3)
Java设计模式-原型模式(3)
|
5月前
|
设计模式 JavaScript 前端开发
从工厂到单例再到策略:Vue.js高效应用JavaScript设计模式
【8月更文挑战第30天】在现代Web开发中,结合使用JavaScript设计模式与框架如Vue.js能显著提升代码质量和项目的可维护性。本文探讨了常见JavaScript设计模式及其在Vue.js中的应用。通过具体示例介绍了工厂模式、单例模式和策略模式的应用场景及其实现方法。例如,工厂模式通过`NavFactory`根据用户角色动态创建不同的导航栏组件;单例模式则通过全局事件总线`eventBus`实现跨组件通信;策略模式用于处理不同的表单验证规则。这些设计模式的应用不仅提高了代码的复用性和灵活性,还增强了Vue应用的整体质量。
69 1
|
5月前
|
设计模式 JavaScript 前端开发
小白请看 JS大项目宝典:设计模式 教你如何追到心仪的女神
小白请看 JS大项目宝典:设计模式 教你如何追到心仪的女神
|
5月前
|
Web App开发 JavaScript 前端开发
Node.js与Go语言的对比?
【8月更文挑战第4天】Node.js与Go语言的对比?
434 3
|
5月前
|
自然语言处理 JavaScript 前端开发
【走向世界】Vue.js国际化:打造无国界应用,让爱与信息跨越语言的边界!
【8月更文挑战第30天】本文详细介绍了Vue.js中实现国际化的多种方法及最佳实践。通过使用`vue-i18n`等第三方库,开发者能够轻松地为应用添加多语言支持,优化用户体验并扩大市场覆盖范围。文章涵盖从基本配置、动态加载语言包到考虑文化差异等方面的内容,帮助读者构建真正全球化且无缝多语言体验的应用程序。
137 0