前端开发之迭代器模式

news2024/11/25 4:30:35

在前端开发中,设计模式是提升代码可读性、可扩展性和可维护性的关键。迭代器模式(Iterator Pattern)是行为型设计模式中的一种,能够让我们顺序访问一个集合中的元素,而不暴露其底层的结构。在 TypeScript 这样具有类型检查的语言中,迭代器模式应用更加方便。

简单for循环

迭代器模式解决的问题是如何更加方便,更加简易,更加友好地去遍历一个顺序集合。用for循环不就行了?不行,普通for循环不是迭代器,它有两个缺点,不符合我们的设计原则。

const arr = [10, 20, 30]
const length = arr.length
for (let i = 0; i < length; i++) {
  console.log(arr[i])
}

如上代码,首先需要知道数组的长度 length ,需要知道如何获取数组的元素 arr[i] 。这样就不符合高内聚低耦合的设计原则,这样数组的很多信息就被公开了。作为一个数组被公开没什么问题,但是如果这个数组是一个比较复杂的数据结构呢?或者第三方服务呢?把场景放大就会是很大的问题。所以普通for循环不是迭代器,迭代器解决的问题是解决数据源里面数据不确定问题、数据封装问题,更好地遍历有序集合的问题。

简易迭代器

const pList = document.querySelectorAll("p");
pList.forEach((p) => console.log(p));

这里没有使用for循环,而使用forEach,本质的区别是,forEach遍历的时候,不需要知道数组长度,也不需要知道怎么获取一个 元素,它直接通过参数传过来了。 

迭代器模式

UML类图如下:


class DataIterator {
  private data: number[];
  private index: number = 0;

  constructor(container: DataContainer) {
    this.data = container.data;
  }
  next() {
    if (this.hasNext()) {
      return this.data[this.index++];
    }
    return null;
  }
  hasNext() {
    return this.index < this.data.length;
  }
}

class DataContainer {
  data = [10, 11, 12, 13, 14, 15];
  getIterator() {
    return new DataContainer(this);
  }
}

const dataContainer = new DataContainer();
const dataIterator = new DataIterator(dataContainer);
while (dataIterator.hasNext()) {
  console.log(dataIterator.next());
}

以上输出结果和for循环遍历是一样的,但我们费这么大力气是为了什么呢?就是为了掩饰迭代器背后它是怎样不用for循环,不用获取长度、不用通过index获取数据的这种高内聚低耦合的方式,更符合设计原则:使用者和目标分离解耦;目标能自行控制其内部逻辑;使用者不关心目标的内部结构。 

 迭代器场景

1. 有序结构。包含:字符串、数组、NodeList等DOM集合、Map、Set、arguments

2. Symbol.iterator

所有有序对象,都内置Symbol.iterator方法,执行该方法,会返回一个迭代器对象。

done为false,说明还没有到最后一个。和我们的 hasNext() 差不多。

我们可以自己定义一个迭代器。

interface IteratorRes {
  value: number | undefined;
  done: boolean;
}

class CustomIterator {
  private length = 3;
  private index = 0;

  next(): IteratorRes {
    this.index++;
    if (this.index <= this.length) {
      return { value: this.index, done: false };
    }
    return { value: undefined, done: true };
  }
  [Symbol.iterator]() {
    return this;
  }
}

const customIterator = new CustomIterator();
console.log(customIterator.next());
console.log(customIterator.next());
console.log(customIterator.next());
console.log(customIterator.next());

迭代器作用

1. 用于for of

只要有内置了Symbol.iterator,都可以执行。

const set = new Set([1, 2, 3]);
for (const num of set) {
  console.log(num);
}
const pList = document.querySelectorAll("p");
for (const p of pList) {
  console.log(p);
}
// 包括我们上面的例子
const customIterator = new CustomIterator();
for (const ci of customIterator) {
  console.log(ci);

2. 数组解构、扩展操作符、Array.from (可用于有任何迭代器模式的数据结构)

// 解构 数组
const arr = [10, 11, 12];
const [a1, a2] = arr;
console.log("a1", a1); // 10
console.log("a2", a2); // 11
// 解构 Set
const set = new Set([100, 200, 300]);
const [s1, s2] = set;
console.log("s1", s1); // 100
console.log("s2", s2); // 200

// 扩展操作符
const arr = [10, 11, 12];
console.log([...arr]) // [10, 11, 12]
const set = new Set([100, 200, 300]);
console.log([...set]) // [100, 200, 300]

// Array.form
console.log(Array.from(set)) // [100, 200, 300]

3. 用于创建Map和Set

4. 用于 Promise.all 和 Promise.race

5. 用于 yield*

Generator 生成器

function* getNums(){
    yield 10
    yield 20
    yield 30
}
const iterator = getNums()
console.log(iterator.next()) // {value: 10, done: false}
console.log(iterator.next()) // {value: 20, done: false}
console.log(iterator.next()) // {value: 30, done: false}
console.log(iterator.next()) // {value: undefined, done: true}
// 将上面的 console.log注释,接下来使用 for of
for (const number of iterator) {
    console.log(number) // 10 20 30
}

可见生成器返回的就是一个迭代器。

function* getNums(){
    yield* [10,20,30] // 有序结构,已经实现了[Symbol.Iterator]
}
const iterator = getNums()
for (const number of iterator) {
    console.log(number) // 10,20,30
}

接下来重构一下上面的 CustomIterator

class CustomIterator {
  private data: number[];
  constructor() {
    this.data = [10, 20, 30];
  }
  *[Symbol.iterator]() {
    yield* this.data;
  }
}
const iterator = new CustomIterator();
for (const n of iterator) {
  console.log(n); // 10 20 30
}

接下来我们使用 Generator + yield 深度优先遍历 DOM 树

<div id="app">
  <p>
    <b>hello</b>
    <i>world</i>
  </p>
  <p>
    <img src="https://www.baidu.com/img/PCfb_5bf082d29588c07f842ccde3f97243ea.png" />
  </p>
</div>
function* traverse(elementList: Element[]): any {
  for (const element of elementList) {
    yield element;
    const children = Array.from(element.children);
    if (children.length) {
      yield* traverse(children);
    }
  }
}
const iterator = document.getElementById("app");
if (iterator) {
  for (const iteratorElement of traverse([iterator])) {
    console.log(iteratorElement);
  }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2129213.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

空间解析几何 1 :空间中直线、圆、椭圆的方程表示

所谓空间解析几何&#xff0c;就是在三维空间中&#xff0c;求两个图形的空间关系&#xff0c;如距离&#xff0c;夹角&#xff0c;这一张给出常用的三个图形&#xff0c;直线&#xff0c;圆&#xff0c;椭圆的空间方程&#xff0c;后面会经常用到。 下一章&#xff1a;空间解析…

APP渗透思路小记

免责声明:本文仅做分享! 目录 协议 反代理 反证书 真实手机抓包: 1-查看本地pc 的 ip. 2-打开bp,配置 ip 及 端口. 3-手机设置代理: 4-手机访问 ip:port 5-安装证书 检查抓包 模拟器抓包: 开源移动端扫描工具 mobsf AppinfoScanner Frida r0capture proxifier…

新能源汽车 BMS 学习笔记篇——如何选择继电器 MOS 管作为开关

序&#xff1a;继电器和 MOSFET&#xff08;俗称 MOS 管&#xff09;都可以用作 BMS&#xff08;Battery Management System&#xff0c;电池管理系统&#xff09; 中控制电池充放电的开关&#xff0c;但它们在原理、结构和特性上存在一些区别&#xff0c;以下总结它们之间主要…

如何本地部署Ganache并使用内网穿透配置公网地址远程连接测试网络

目录 前言 1. 安装Ganache 2. 安装cpolar 3. 创建公网地址 4. 公网访问连接 5. 固定公网地址 作者简介&#xff1a; 懒大王敲代码&#xff0c;计算机专业应届生 今天给大家聊聊如何本地部署Ganache并使用内网穿透配置公网地址远程连接测试网络&#xff0c;欢迎大家点赞 &a…

rocm Linpack 编译构建系统解析

0. 购买amd显卡&#xff0c;安装rocm 1, 编译 rocHPL 下载源码&#xff1a; $ git clone --recursive https://github.com/ROCm/rocHPL.git 编译&#xff1a; $ cd rocHPL/ $ ./install.sh --prefix${PWD}/../local/ 会自动 git clone blit,ucx,opempi, $ ./mpirun_rochpl …

【hot100-java】【接雨水】

R8-双指针篇 转战java后端的第一天&#xff0c;学点java语法&#xff08;手动狗头&#xff09; 这题之前写过多种解法 下面我们使用前后缀分离法解决。 class Solution {public int trap(int[] height) {int n height.length;//表示height[0]到height[i]的最大值int[] pre…

【mechine learning-七-线性回归之成本函数】

监督学习之cost function 成本函数权重、偏置如何实现拟合数据成本函数是如何寻找出来w和b&#xff0c;使成本函数值最小化&#xff1f; 在线性回归中&#xff0c;我们说到评估模型训练中好坏的一个方法&#xff0c;是用成本函数来衡量&#xff0c;下面来详细介绍一下 成本函数…

3D技术在电商独立站中的应用有哪些?

3D技术在电商独立站中的应用日益广泛&#xff0c;为电商行业带来了全新的商品展示方式和购物体验。以下是3D技术在电商独立站中的具体应用及其带来的优势&#xff1a; 一、商品3D展示 1、沉浸式体验&#xff1a; 通过3D技术&#xff0c;商品可以在独立站上以三维形式呈现&…

Word 脚注与正文之间的空行怎么删除啊?

全网都搜索不到解决方案&#xff0c;难道只有我一个人遇到这个问题了吗&#xff1f; 无语&#xff0c;。、;

9月12日的学习

练习 #include "widget.h" #include "ui_widget.h" QListWidgetItem *p; Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget),socket(new QTcpSocket(this))//给客户端指针实例化空间及关联父组件 {ui->setupUi(this);//初始化,ui-…

学习大数据DAY56 业务理解和第一次接入

作业1 1 了解行业名词 ERP CRM OA MES WMS RPA SAAS 了解每个系统的功能和应用 ERP 系统&#xff0c;&#xff08;Enterprise Resource Planning&#xff0c;企业资源计划系统&#xff09;&#xff1a;ERP 系统 是一种用于管理企业各类资源的软件系统&#xff0c;包括生产管理…

2024年软件测试经典大厂面试题(全3套)【包含答案】

前言 金三银四即将过去&#xff0c;后面迎来的便是金九银十&#xff0c;一直想着说分享一些软件测试的面试题&#xff0c;这段时间做了一些收集和整理&#xff0c;下面共有三篇经典面试题&#xff0c;大家可以试着做一下&#xff0c;答案附在后面&#xff0c;希望能帮助到大家。…

STM32——玩转超声波传感器

目录 1.什么是超声波&#xff1f; 超声波的基本特点&#xff1a; 2.超声波传感器介绍&#xff1a;HC-SR04 HC-SR04 主要特点&#xff1a; HC-SR04 接线如下&#xff1a; HC-SR04 工作原理&#xff1a; 如何编写超声波测距代码&#xff1f; 编写逻辑&#xff1a; 编写思…

【2024】前端学习笔记4-图像标记

在 HTML 中&#xff0c;<img>标签用于在网页中插入图像。 基本语法&#xff1a; <img src"图像文件地址" alt"替代文本">src&#xff1a;指定图片的路径&#xff0c;可以是相对路径、绝对路径。alt&#xff1a;为图像提供代替文本&#xff0…

9.12日常记录

1.extern关键字 1&#xff09;诞生动机:在一个C语言项目中&#xff0c;需要再多个文件中使用同一全局变量或是函数&#xff0c;那么就需要在这些文件中再声明一遍 2&#xff09;用于声明在其他地方定义的一个变量或是函数&#xff0c;在当前位置只是声明&#xff0c;告诉编译器…

【办公类】幼儿健康数据模版批量更改日期(保健老师填写)

背景需求 今天下发通知 三个园区的保健老师需要填写 1.2023学年&#xff08;202406&#xff09;的六一体检数据 2.2024学年&#xff08;202409&#xff09;的新生入园体检数据 我先把上一轮填写过的数据模版下载下来&#xff08;套用模版&#xff09; 把EXCEL下载到原始文件…

驾驭不断发展的人工智能世界

从很多方面来看&#xff0c;历史似乎正在重演。许多企业正争相采用生成式人工智能 (Gen AI)&#xff0c;就像它们争相采用云计算一样&#xff0c;原因也是一样的&#xff1a;效率、成本节约和竞争优势。 然而&#xff0c;与云一样&#xff0c;GenAI 仍是一项发展中的技术&…

机器学习(西瓜书)第 9 章 聚类

9.1 聚类任务和距离计算 在”无监督学习“中&#xff0c;训练样本的标记信息是未知的&#xff0c;目标是通过对无标记训练样本的学习来揭示数据的内在性质及规律&#xff0c;为进一步的数据分析提供基础.此类学习任务中研究最多、应用最广的是“聚类”(clustering). 聚类试图…

咖啡果实病虫害检测系统源码分享

咖啡果实病虫害检测检测系统源码分享 [一条龙教学YOLOV8标注好的数据集一键训练_70全套改进创新点发刊_Web前端展示] 1.研究背景与意义 项目参考AAAI Association for the Advancement of Artificial Intelligence 项目来源AACV Association for the Advancement of Comput…

【最新综述】基于深度学习的超声自动无损检测(上)

Deep learning in automated ultrasonic NDE – Developments, axioms and opportunities 传统上&#xff0c;超声无损检测数据分析一直由训练有素的操作员在基本自动化工具的支持下手动解释数据。最近&#xff0c;开始出现许多针对个别无损检测任务&#xff08;数据预处理、缺…