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);
目录
相关文章
|
14天前
|
设计模式 Java 关系型数据库
【Java笔记+踩坑】设计模式——原型模式
对比原型模式和传统方式的实现思路、代码方案、优缺点,阐述原型模式的使用场景,以及深拷贝、浅拷贝等相关概念,并扩展原型模式在Spring源码中的应用。
【Java笔记+踩坑】设计模式——原型模式
|
2天前
|
设计模式 Java
Java设计模式-原型模式(3)
Java设计模式-原型模式(3)
Java设计模式-原型模式(3)
|
29天前
|
自然语言处理 JavaScript 前端开发
【走向世界】Vue.js国际化:打造无国界应用,让爱与信息跨越语言的边界!
【8月更文挑战第30天】本文详细介绍了Vue.js中实现国际化的多种方法及最佳实践。通过使用`vue-i18n`等第三方库,开发者能够轻松地为应用添加多语言支持,优化用户体验并扩大市场覆盖范围。文章涵盖从基本配置、动态加载语言包到考虑文化差异等方面的内容,帮助读者构建真正全球化且无缝多语言体验的应用程序。
56 0
|
29天前
|
设计模式 JavaScript 前端开发
从工厂到单例再到策略:Vue.js高效应用JavaScript设计模式
【8月更文挑战第30天】在现代Web开发中,结合使用JavaScript设计模式与框架如Vue.js能显著提升代码质量和项目的可维护性。本文探讨了常见JavaScript设计模式及其在Vue.js中的应用。通过具体示例介绍了工厂模式、单例模式和策略模式的应用场景及其实现方法。例如,工厂模式通过`NavFactory`根据用户角色动态创建不同的导航栏组件;单例模式则通过全局事件总线`eventBus`实现跨组件通信;策略模式用于处理不同的表单验证规则。这些设计模式的应用不仅提高了代码的复用性和灵活性,还增强了Vue应用的整体质量。
21 0
|
1月前
|
Web App开发 JavaScript 前端开发
Node.js与Go语言的对比?
【8月更文挑战第4天】Node.js与Go语言的对比?
192 3
|
1月前
|
设计模式 JavaScript 前端开发
小白请看 JS大项目宝典:设计模式 教你如何追到心仪的女神
小白请看 JS大项目宝典:设计模式 教你如何追到心仪的女神
|
1月前
|
JavaScript 前端开发 UED
探索JavaScript的历史:网络需求初现、语言创立与标准化的旅程
探索JavaScript的历史:网络需求初现、语言创立与标准化的旅程
|
2月前
|
设计模式
iLogtail设计模式问题之iLogtail中的原型模式是什么
iLogtail设计模式问题之iLogtail中的原型模式是什么
iLogtail设计模式问题之iLogtail中的原型模式是什么
|
2月前
|
设计模式 Go
Go语言设计模式:使用Option模式简化类的初始化
在Go语言中,面对构造函数参数过多导致的复杂性问题,可以采用Option模式。Option模式通过函数选项提供灵活的配置,增强了构造函数的可读性和可扩展性。以`Foo`为例,通过定义如`WithName`、`WithAge`、`WithDB`等设置器函数,调用者可以选择性地传递所需参数,避免了记忆参数顺序和类型。这种模式提升了代码的维护性和灵活性,特别是在处理多配置场景时。
62 8
|
2月前
|
设计模式 JavaScript Go
js设计模式【详解】—— 状态模式
js设计模式【详解】—— 状态模式
44 7