当前位置: 首页 > article >正文

JS面相对象小案例:自定义安全数组

在JS中,数组不像其他语言(java、python)中那样安全,它具有动态性和弱类型性,切越界访问没有具体的报错,而是返回空,为提升数组的安全性,我们可以自行定义一个安全数组。

一、增加报错

与其他语言一样,增加IndexError,继承内置的Error对象。示例如下:

class IndexError extends Error {constructor(message) {super(message);this.name = "索引越界";}
}

这样,我们就可以通过throw语句,抛出new IndexError()异常。

二、定义安全数组类SafeArray

这里,可以使用ES6语法来定义,结构比较简单,也容易理解,示例如下:

class SafeArray {#_array;constructor(...initialArray) {// 约定的私有属性this.#_array = [...initialArray];}
}

注意:上面代码中的 # 表示定义一个私有属性或方法(也就是说,只能在内部访问,不能在类的外部进行访问。),并不是所有的编译器都支持。因为它是ECMAScript 2022新增的语法。

三、添加你想要的getter和setter

1、返回长度

    // 获取数组的长度get length() {return this.#_array.length;}

这样,我们调用new SafeArray().length,就能得到安全数组的长度

2、可以添加sum属性

    // 求和get sum() {return this.#_array.reduce((s, elt) => s+=elt, 0);}

这样,调用.sum,就能计算数组中各元素相加的和,壮大了内置数组Array的功能。照这个思路,还可以添加更多的聚合函数,如求平均、最值等等。

四、编写安全数组的方法

确定好结构,与必要的属性之后,我们需要为安全数组提供一些必要的方法,如安全的获取元素,安全的添加元素,安全的查找元素等等。示例如下:

    #_isValidIndex(index) {return Number.isInteger(index) && index >= 0 && index < this.#_array.length;}// 安全地获取索引处的值,如果索引无效则返回undefinedgetItem(index) {if (this.#_isValidIndex(index)) {return this.#_array[index];}throw new IndexError("数组索引超出范围");}// 安全地设置索引处的值,如果索引无效则不进行操作setItem(index, value) {if (this.#_isValidIndex(index)) {this.#_array[index] = value;} else {throw new IndexError("数组索引超出范围");}}// 获取指定元素的索引indexOf(value, start) {return this.#_array.indexOf(value, start); // 不存在返回 -1}// 判断某个元素是否包含在数组中(适用于判断对象数组或较为复杂的数组中的元素,但存在性能影响)contains(value) {let arr = this.#_array;for (let i = 0; i < arr.length; i++) {if (JSON.stringify(arr[i]) === JSON.stringify(value)) return true;}return false;}// 简单的判断某个元素是否包含在数组中includes(value) {return this.#_array.includes(value);}// 切片slice(start, end) {return this.#_array.slice(start, end);}

上述代码中,如果数组索引超出范围,就会抛出索引越界的错误,这是内置数组做不到的。

五、完整代码

class IndexError extends Error {constructor(message) {super(message);this.name = "索引越界";}
}class SafeArray {constructor(...initialArray) {// 约定的私有属性this.#_array = [...initialArray];}// 获取数组的长度get length() {return this.#_array.length;}// 求和get sum() {return this.#_array.reduce((s, elt) => s+=elt, 0);}// 求平均get average() {if(this.length === 0) throw new Error("数组为空,无法计算");return this.sum / this.length;}// 最大值get max() {return Math.max(...this.#_array);}// 最小值get min() {return Math.min(...this.#_array);}// 返回数组的维度(复杂度较高)get dimension() {let r = 0, max = 0;let stack = [{ array: this.#_array, depth: 0 }];while (stack.length > 0) {let { array, depth } = stack.pop();if (Array.isArray(array)) {r = depth + 1;// 将当前数组的所有元素推入栈中,并增加深度for (let item of array) {stack.push({ array: item, depth: r });}// 更新最大维度max = Math.max(max, r);}}return max;}// 安全地获取索引处的值,如果索引无效则返回undefinedgetItem(index) {if (this.#_isValidIndex(index)) {return this.#_array[index];}throw new IndexError("数组索引超出范围");}// 安全地设置索引处的值,如果索引无效则不进行操作setItem(index, value) {if (this.#_isValidIndex(index)) {this.#_array[index] = value;} else {throw new IndexError("数组索引超出范围");}}// 获取指定元素的索引indexOf(value, start) {return this.#_array.indexOf(value, start); // 不存在返回 -1}// 判断某个元素是否包含在数组中(适用于判断对象数组或较为复杂的数组中的元素,但存在性能影响)contains(value) {let arr = this.#_array;for (let i = 0; i < arr.length; i++) {if (JSON.stringify(arr[i]) === JSON.stringify(value)) return true;}return false;}// 简单的判断某个元素是否包含在数组中includes(value) {return this.#_array.includes(value);}// 切片slice(start, end) {return this.#_array.slice(start, end);}// 添加到数组的开头unshift(value) {this.#_array.unshift(value);}// 添加元素到数组末尾push(value) {this.#_array.push(value);}// 移除数组末尾的元素pop() {return this.#_array.pop();}// 移除数组开头的元素shift() {return this.#_array.shift();}// joinjoin(delimiter) {return this.#_array.join(delimiter);}// concatconcat(...other) {return this.#_array.concat(...other);}// 在指定索引处插入元素,如果索引无效则插入到末尾insert(index, value) {if (this.#_isValidIndex(index)) {this.#_array.splice(index, 0, value);} else {this.#_array.push(value);}}// 移除指定索引的元素,如果索引无效则不进行操作remove(index) {if (this.#_isValidIndex(index)) {return this.#_array.splice(index, 1)[0];} else {throw new IndexError("数组索引超出范围");}}// 返回数组的字符串表示toString() {return this.#_array.toString();}// 排序sort(callback) {if(callback === undefined) callback = function(){return undefined};this.#_notFuncError(callback, "callback");return this.#_array.sort(callback);}// reducereduce(callback, init) {if(callback === undefined) callback = function(){};this.#_notFuncError(callback, "callback");return this.#_array.reduce(callback, init);}// forEachforEach(callback) {if(callback === undefined) callback = function(){};this.#_notFuncError(callback, "callback");this.#_array.forEach(callback);}// Mapmap(callback) {if(callback === undefined) callback = function(){};this.#_notFuncError(callback, "callback");return this.#_array.map(callback);}// filterfilter(conditionFunction) {if(conditionFunction === undefined) conditionFunction = function(){return true};this.#_notFuncError(conditionFunction, "conditionFunction");return this.#_array.filter(conditionFunction);}// findfind(callback) {if(callback === undefined) callback = function(){};this.#_notFuncError(callback, "callback");return this.#_array.find(callback);}// findIndexfindIndex(callback) {if(callback === undefined) callback = function(){};this.#_notFuncError(callback, "callback");return this.#_array.findIndex(callback);}// everyevery(conditionFunction, context) {if(conditionFunction === undefined) conditionFunction = function(){return false};this.#_notFuncError(conditionFunction, "conditionFunction");return this.#_array.every(conditionFunction, context);}// somesome(conditionFunction, context) {if(conditionFunction === undefined) conditionFunction = function(){return false};this.#_notFuncError(conditionFunction, "conditionFunction");return this.#_array.some(conditionFunction, context);}// 检查是不是数组static isArray(arr) {return Array.isArray(arr);}// 检查是不是安全数组static isSafeArray(arr) {return arr instanceof SafeArray;}// 检查索引是否有效#_isValidIndex(index) {return Number.isInteger(index) && index >= 0 && index < this.#_array.length;}// 不是函数的固定报错#_notFuncError(fn, c) {if(typeof fn !== "function") throw new TypeError("参数" + c + "不是函数");}// 私有属性#_array;}

上述是一个完整的SafeArray类是一个功能丰富且安全的数组实现,它通过封装和私有化内部状态,提供了对数组操作的更高层次的控制和安全性。尽管在某些方面可能存在性能开销,但它为需要严格数据完整性和安全性的场景提供了有用的工具。

相关文章:

JS面相对象小案例:自定义安全数组

在JS中&#xff0c;数组不像其他语言&#xff08;java、python&#xff09;中那样安全&#xff0c;它具有动态性和弱类型性&#xff0c;切越界访问没有具体的报错&#xff0c;而是返回空&#xff0c;为提升数组的安全性&#xff0c;我们可以自行定义一个安全数组。 一、增加报…...

Microsoft Power BI:融合 AI 的文本分析

Microsoft Power BI 是微软推出的一款功能强大的商业智能工具&#xff0c;旨在帮助用户从各种数据源中提取、分析和可视化数据&#xff0c;以支持业务决策和洞察。以下是关于 Power BI 的深度介绍&#xff1a; 1. 核心功能与特点 Power BI 提供了全面的数据分析和可视化功能&…...

如何实现滑动列表功能

文章目录 1 概念介绍2 使用方法3 示例代码 我们在上一章回中介绍了沉浸式状态栏相关的内容&#xff0c;本章回中将介绍SliverList组件.闲话休提&#xff0c;让我们一起Talk Flutter吧。 1 概念介绍 我们在这里介绍的SliverList组件是一种列表类组件&#xff0c;类似我们之前介…...

计算机网络一点事(23)

传输层 端口作用&#xff1a;标识主机特定进程&#xff0c;TCP&#xff0c;UDP协议 端口号分类&#xff1a;服务器&#xff1a;0-1023&#xff0c;熟知 1024-49151 登记 客户端&#xff1a;49152-65535 功能&#xff1a;实现端到端&#xff0c;进程到进程的通信&#xff0c…...

Linux——网络(tcp)

文章目录 目录 文章目录 前言 一、TCP逻辑 1. 面向连接 三次握手&#xff08;建立连接&#xff09; 四次挥手&#xff08;关闭连接&#xff09; 2. 可靠性 3. 流量控制 4. 拥塞控制 5. 基于字节流 6. 全双工通信 7. 状态机 8. TCP头部结构 9. TCP的应用场景 二、编写tcp代码函数…...

算法题(54):插入区间

审题&#xff1a; 需要我们把newinterval的区间与interval的区间合并起来&#xff0c;并返回合并后的二维数组地址 思路&#xff1a; 方法一&#xff1a;排序合并区间 我们可以先把newinterval插入到interval中&#xff0c;进行排序然后复用合并区间的代码 方法二&#xff1a;模…...

UE学习日志#18 C++笔记#4 基础复习4 指派初始化器和指针

1 指派初始化器 C20引入了指派初始化器&#xff0c;以使用他们的名称初始化所谓聚合的数据成员。 聚合类型是满足以下限制的数组类型的对象或结构或类的对象&#xff1a; 1.仅public数据成员&#xff0c; 2.无用户声明或继承的构造函数&#xff0c; 3.无虚函数和无虚基类、priv…...

【算法】回溯算法专题① ——子集型回溯 python

目录 引入变形实战演练总结 引入 子集 https://leetcode.cn/problems/subsets/description/ 给你一个整数数组 nums &#xff0c;数组中的元素 互不相同 。返回该数组所有可能的子集&#xff08;幂集&#xff09;。 解集 不能 包含重复的子集。你可以按 任意顺序 返回解集。 …...

Gradle配置指南:深入解析settings.gradle.kts(Kotlin DSL版)

文章目录 Gradle配置指南&#xff1a;深入解析settings.gradle.kts&#xff08;Kotlin DSL版&#xff09;settings.gradle.kts 基础配置选项单项目配置多项目配置 高级配置选项插件管理&#xff08;Plugin Management&#xff09;基础配置模板案例&#xff1a;Android项目标准配…...

makailio-alias_db模块详解

ALIAS_DB 模块 作者 Daniel-Constantin Mierla micondagmail.com Elena-Ramona Modroiu ramonaasipto.com 编辑 Daniel-Constantin Mierla micondagmail.com 版权 © 2005 Voice Sistem SRL © 2008 asipto.com 目录 管理员指南 概述依赖 2.1 Kamailio 模块 2.2 外…...

【机器学习】自定义数据集 使用pytorch框架实现逻辑回归并保存模型,然后保存模型后再加载模型进行预测,对预测结果计算精确度和召回率及F1分数

一、使用pytorch框架实现逻辑回归 1. 数据部分&#xff1a; 首先自定义了一个简单的数据集&#xff0c;特征 X 是 100 个随机样本&#xff0c;每个样本一个特征&#xff0c;目标值 y 基于线性关系并添加了噪声。将 numpy 数组转换为 PyTorch 张量&#xff0c;方便后续在模型中…...

Spring Boot - 数据库集成06 - 集成ElasticSearch

Spring boot 集成 ElasticSearch 文章目录 Spring boot 集成 ElasticSearch一&#xff1a;前置工作1&#xff1a;项目搭建和依赖导入2&#xff1a;客户端连接相关构建3&#xff1a;实体类相关注解配置说明 二&#xff1a;客户端client相关操作说明1&#xff1a;检索流程1.1&…...

Java篇之继承

目录 一. 继承 1. 为什么需要继承 2. 继承的概念 3. 继承的语法 4. 访问父类成员 4.1 子类中访问父类的成员变量 4.2 子类中访问父类的成员方法 5. super关键字 6. super和this关键字 7. 子类构造方法 8. 代码块的执行顺序 9. protected访问修饰限定符 10. 继承方式…...

32. C 语言 安全函数( _s 尾缀)

本章目录 前言什么是安全函数&#xff1f;安全函数的特点主要的安全函数1. 字符串操作安全函数2. 格式化输出安全函数3. 内存操作安全函数4. 其他常用安全函数 安全函数实例示例 1&#xff1a;strcpy_s 和 strcat_s示例 2&#xff1a;memcpy_s示例 3&#xff1a;strtok_s 总结 …...

ArkTS编程规范

文章目录 目标和适用范围规则来源章节概览代码风格编程实践 术语和定义总体原则命名类名、枚举名、命名空间名采用UpperCamelCase风格变量名、方法名、参数名采用lowerCamelCase风格常量名、枚举值名采用全部大写&#xff0c;单词间使用下划线隔开避免使用否定的布尔变量名&…...

SQL进阶实战技巧:断点去重技术详解

目录 一、核心概念 二、典型应用场景 三、实现步骤与SQL示例 场景 目标 步骤 分析 结果 四、核心原理解释 1. 核心原理&#xff1a;相邻比较 2. 去重的本质 3. 与传统方法的对比 4 类别理解 五、如何应对复杂场景&#xff1f; 1. 多字段断点检测 2. 时间窗口断点 …...

深度学习之“向量范数和距离度量”

在深度学习中&#xff0c;范数和向量距离是两个不同的概念。向量范数是一种函数&#xff0c;用于将一个实数或复数向量映射为一个值。虽然范数通常用于度量向量之间的距离&#xff0c;但是同样也有其它的一些表示距离的方式。 范数距离 范数是具有“长度”概念的函数。在向量…...

基于Python的简单企业维修管理系统的设计与实现

以下是一个基于Python的简单企业维修管理系统的设计与实现&#xff0c;这里我们会使用Flask作为Web框架&#xff0c;SQLite作为数据库来存储相关信息。 1. 需求分析 企业维修管理系统主要功能包括&#xff1a; 维修工单的创建、查询、更新和删除。设备信息的管理。维修人员…...

javascript常用函数大全

javascript函数一共可分为五类&#xff1a; •常规函数 •数组函数 •日期函数 •数学函数 •字符串函数 1.常规函数 javascript常规函数包括以下9个函数&#xff1a; (1)alert函数&#xff1a;显示一个警告对话框&#xff0c;包括一个OK按钮。 (2)confirm函数&#xff1a;显…...

【Leetcode 每日一题】81. 搜索旋转排序数组 II

问题背景 已知存在一个按非降序排列的整数数组 n u m s nums nums&#xff0c;数组中的值不必互不相同。 在传递给函数之前&#xff0c; n u m s nums nums 在预先未知的某个下标 k ( 0 < k < n u m s . l e n g t h ) k\ (0 < k < nums.length) k (0<k<…...

< OS 有关 > Android 手机 SSH 客户端 app: connectBot

connectBot 开源且功能齐全的SSH客户端,界面简洁,支持证书密钥。 下载量超 500万 方便在 Android 手机上&#xff0c;连接 SSH 服务器&#xff0c;去运行命令。 Fail2ban 12小时内抓获的 IP ~ ~ ~ ~ rootjpn:~# sudo fail2ban-client status sshd Status for the jail: sshd …...

【算法设计与分析】实验7:复杂装载及0/1背包问题的回溯法设计与求解

目录 一、实验目的 二、实验环境 三、实验内容 四、核心代码 五、记录与处理 六、思考与总结 七、完整报告和成果文件提取链接 一、实验目的 针对复杂装载问题、及0/1背包问题开展分析、建模、评价&#xff0c;算法设计与优化&#xff0c;并进行编码实践。 理解复杂装载…...

仿真设计|基于51单片机的温湿度、一氧化碳、甲醛检测报警系统

目录 具体实现功能 设计介绍 51单片机简介 资料内容 仿真实现&#xff08;protues8.7&#xff09; 程序&#xff08;Keil5&#xff09; 全部内容 资料获取 具体实现功能 &#xff08;1&#xff09;温湿度传感器、CO传感器、甲醛传感器实时检测温湿度值、CO值和甲醛值进…...

使用vhd虚拟磁盘安装两个win10系统

使用vhd虚拟磁盘安装两个win10系统 前言vhd虚拟磁盘技术简介准备工具开始动手实践1.winX选择磁盘管理2.选择“操作”--“创建VHD”3.自定义一个位置&#xff0c;输入虚拟磁盘大小4.右键初始化磁盘5.选择GPT分区表格式6.右键新建简单卷7.给卷起个名字&#xff0c;用于区分8.打开…...

Python学习——函数参数详解

Python中的函数参数传递机制允许多种灵活的参数类型&#xff0c;可以根据需求灵活配置参数&#xff0c;这使得函数具有更强大的扩展性和适应性。以下是对各类参数类型的详细说明&#xff1a; 1. 定义函数的不同参数类型 1.1 位置参数 定义方式&#xff1a;def func(a, b2) 特…...

深入理解Spring事务管理

一、事务基础概念 1.1 什么是事务&#xff1f; 事务&#xff08;Transaction&#xff09;是数据库操作的最小工作单元&#xff0c;具有ACID四大特性&#xff1a; 原子性&#xff08;Atomicity&#xff09;&#xff1a;事务中的操作要么全部成功&#xff0c;要么全部失败 一致…...

自制虚拟机(C/C++)(二、分析引导扇区,虚拟机读二进制文件img软盘)

先修复上一次的bug&#xff0c;添加新指令&#xff0c;并增加图形界面 #include <graphics.h> #include <conio.h> #include <windows.h> #include <commdlg.h> #include <iostream> #include <fstream> #include <sstream> #inclu…...

基于最近邻数据进行分类

人工智能例子汇总:AI常见的算法和例子-CSDN博客 完整代码: import torch import numpy as np from sklearn.neighbors import KNeighborsClassifier from sklearn.metrics import accuracy_score import matplotlib.pyplot as plt# 生成一个简单的数据集 (2个特征和2个分类…...

ASP.NET Core 启动并提供静态文件

ASP.NET Core 启动并提供静态文件 即是单个可执行文件&#xff0c;它既运行 API 项目&#xff0c;也托管 前端项目&#xff08;通常是前端的发布文件&#xff09;。 这种方式一般是通过将 前端项目 的发布文件&#xff08;例如 HTML、CSS、JavaScript&#xff09;放入 Web AP…...

【异步编程】CompletableFuture:异步任务的选择(执行最快的)执行

文章目录 一. applyToEither : 拿到第一个任务结束的结果二. runAfterEither &#xff1a;第一个任务完成后执行副作用三. acceptEither&#xff1a;消费第一个任务的结果四. 三种接口总结 对于两个异步任务&#xff0c;我们有时希望在其中一个任务完成时立即执行某些操作&…...