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

news2025/2/3 2:52:42

在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;
    }

    // 安全地获取索引处的值,如果索引无效则返回undefined
    getItem(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;
    }

    // 安全地获取索引处的值,如果索引无效则返回undefined
    getItem(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();
    }
    
    // join
    join(delimiter) {
    	return this.#_array.join(delimiter);
    }
    
    // concat
    concat(...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);
	}
	
	// reduce
	reduce(callback, init) {
		if(callback === undefined) callback = function(){};
		this.#_notFuncError(callback, "callback");
		return this.#_array.reduce(callback, init);
	}
	
	// forEach
	forEach(callback) {
		if(callback === undefined) callback = function(){};
		this.#_notFuncError(callback, "callback");
		this.#_array.forEach(callback);
	}
	
	// Map
	map(callback) {
		if(callback === undefined) callback = function(){};
		this.#_notFuncError(callback, "callback");
		return this.#_array.map(callback);
	}
	
	// filter
	filter(conditionFunction) {
		if(conditionFunction === undefined) conditionFunction = function(){return true};
		this.#_notFuncError(conditionFunction, "conditionFunction");
		return this.#_array.filter(conditionFunction);
	}
	
	// find
	find(callback) {
		if(callback === undefined) callback = function(){};
		this.#_notFuncError(callback, "callback");
		return this.#_array.find(callback);
	}
	
	// findIndex
	findIndex(callback) {
		if(callback === undefined) callback = function(){};
		this.#_notFuncError(callback, "callback");
		return this.#_array.findIndex(callback);
	}
	
	// every
	every(conditionFunction, context) {
    	if(conditionFunction === undefined) conditionFunction = function(){return false};
		this.#_notFuncError(conditionFunction, "conditionFunction");
    	return this.#_array.every(conditionFunction, context);
    }
    
    // some
    some(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类是一个功能丰富且安全的数组实现,它通过封装和私有化内部状态,提供了对数组操作的更高层次的控制和安全性。尽管在某些方面可能存在性能开销,但它为需要严格数据完整性和安全性的场景提供了有用的工具。

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

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

相关文章

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;类似我们之前介…

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;模…

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

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

【机器学习】自定义数据集 使用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. 继承方式…

ArkTS编程规范

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

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

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

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

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

< 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.打开…

深入理解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…

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

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

4 [危机13小时追踪一场GitHub投毒事件]

事件概要 自北京时间 2024.12.4 晚间6点起&#xff0c; GitHub 上不断出现“幽灵仓库”&#xff0c;仓库中没有任何代码&#xff0c;只有诱导性的病毒文件。当天&#xff0c;他们成为了 GitHub 上 star 增速最快的仓库。超过 180 个虚假僵尸账户正在传播病毒&#xff0c;等待不…

变量和常量

一.变量 1.标准声明 var 变量名 变量类型 变量声明行末不需要分号 2..批量声明 package main import "fmt" func main(){var(a string b int c boold float32)}3.变量的初始化 var a int 10 var b float321.1 4.类型推导 var name"tom" var age18 fmt.Pr…