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類是一個功能豐富且安全的數組實現,它通過封裝和私有化內部狀態,提供了對數組操作的更高層次的控制和安全性。盡管在某些方面可能存在性能開銷,但它為需要嚴格數據完整性和安全性的場景提供了有用的工具。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/67106.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/67106.shtml
英文地址,請注明出處:http://en.pswp.cn/web/67106.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

本地大模型編程實戰(02)語義檢索(2)

文章目錄 準備按批次嵌入加載csv文件&#xff0c;分割文檔并嵌入測試嵌入效果總結代碼 上一篇文章&#xff1a; 本地大模型編程實戰(02)語義檢索(1) 詳細介紹了如何使用 langchain 實現語義檢索&#xff0c;為了演示方便&#xff0c;使用的是 langchain 提供的內存數據庫。 在實…

windows平臺intel-vpl編譯

需要先在本機編譯好opencl庫 git clone --recursive https://github.com/KhronosGroup/OpenCL-SDK.git cmake -A x64 -T v143 -D OPENCL_SDK_BUILD_OPENGL_SAMPLESOFF -B OpenCL-SDK\build -S OpenCL-SDKcmake --build OpenCL-SDK\build --config Releasecmake --install O…

Vue 3 30天精進之旅:Day 05 - 事件處理

引言 在前幾天的學習中&#xff0c;我們探討了Vue實例、計算屬性和偵聽器。這些概念為我們搭建了Vue應用的基礎。今天&#xff0c;我們將專注于事件處理&#xff0c;這是交互式Web應用的核心部分。通過學習如何在Vue中處理事件&#xff0c;你將能夠更好地與用戶進行交互&#…

[C語言日寄]exit函數的使用及其拓展

【作者主頁】siy2333 【專欄介紹】?c語言日寄?&#xff1a;這是一個專注于C語言刷題的專欄&#xff0c;精選題目&#xff0c;搭配詳細題解、拓展算法。從基礎語法到復雜算法&#xff0c;題目涉及的知識點全面覆蓋&#xff0c;助力你系統提升。無論你是初學者&#xff0c;還是…

React 中hooks之useSyncExternalStore使用總結

1. 基本概念 useSyncExternalStore 是 React 18 引入的一個 Hook&#xff0c;用于訂閱外部數據源&#xff0c;確保在并發渲染下數據的一致性。它主要用于&#xff1a; 訂閱瀏覽器 API&#xff08;如 window.width&#xff09;訂閱第三方狀態管理庫訂閱任何外部數據源 1.1 基…

激光雷達和相機早期融合

通過外參和內參的標定將激光雷達的點云投影到圖像上。 ? 傳感器標定 首先需要對激光雷達和相機&#xff08;用于獲取 2D 圖像&#xff09;進行外參和內參標定。這是為了確定激光雷達坐標系和相機坐標系之間的轉換關系&#xff0c;包括旋轉和平移。通常采用棋盤格等標定工具&…

Linux--權限

Linux系統的權限管理是保障系統安全的重要機制&#xff0c;以下詳細講解權限相關概念及操作指令&#xff1a; 一、基礎權限機制 1. 權限的三元組&#xff0c;讀&#xff08;r&#xff09;、寫&#xff08;w&#xff09;、執行&#xff08;x&#xff09; 每個文件或目錄有三組…

iic、spi以及uart

何為總線&#xff1f; 連接多個部件的信息傳輸線&#xff0c;是部件共享的傳輸介質 總線的作用&#xff1f; 實現數據傳輸&#xff0c;即模塊之間的通信 總線如何分類&#xff1f; 根據總線連接的外設屬于內部外設還是外部外設將總線可以分為片內總線和片外總線 可分為數…

“破冰”探索兩周年,AI和媒體碰撞出了什么火花?

2022年末&#xff0c;大模型浪潮席卷而來。在“所有行業都值得用AI重塑”的氛圍下&#xff0c;各個行業都受到了影響和沖擊。 其中新聞媒體可以說是受影響最為劇烈的行業。 因為內容的生產方式被重新定義&#xff0c;媒體從業者普遍存在焦慮情緒&#xff1a;擔心錯過新一輪的…

DeepSeek明確學術研究方向效果如何?

明確學術研究方向 在學術寫作中&#xff0c;選擇一個出色的研究主題至關重要&#xff0c;因為它直接關系到論文是否能登上高級別的學術期刊。不少學者在這個過程中走入了誤區&#xff0c;他們往往將大把的時間花在寫作本身&#xff0c;而忽略了對選題的深入思考&#xff0c;這…

WPF實戰案例 | C# WPF實現大學選課系統

WPF實戰案例 | C# WPF實現大學選課系統 一、設計來源1.1 主界面1.2 登錄界面1.3 新增課程界面1.4 修改密碼界面 二、效果和源碼2.1 界面設計&#xff08;XAML&#xff09;2.2 代碼邏輯&#xff08;C#&#xff09; 源碼下載更多優質源碼分享 作者&#xff1a;xcLeigh 文章地址&a…

《 C++ 點滴漫談: 二十四 》深入 C++ 變量與類型的世界:高性能編程的根基

摘要 本文深入探討了 C 中變量與類型的方方面面&#xff0c;包括變量的基本概念、基本與復合數據類型、動態類型與內存管理、類型推導與模板支持&#xff0c;以及類型系統的高級特性。通過全面的理論講解與實際案例分析&#xff0c;展示了 C 類型系統的強大靈活性與實踐價值。…

STM32 GPIO配置 點亮LED燈

本次是基于STM32F407ZET6做一個GPIO配置&#xff0c;實現點燈實驗。 新建文件 LED.c、LED.h文件&#xff0c;將其封裝到Driver文件中。 雙擊Driver文件將LED.c添加進來 編寫頭文件&#xff0c;這里注意需要將Driver頭文件聲明一下。 在LED.c、main.c里面引入頭文件LED.h LED初…

window保存好看的桌面壁紙

1、按下【WINR】快捷鍵調出“運行”窗口&#xff0c;輸入以下命令后回車。 %localappdata%\Packages\Microsoft.Windows.ContentDeliveryManager_cw5n1h2txyewy\LocalState\Assets 2、依次點擊【查看】【顯示】&#xff0c;勾選【隱藏的項目】&#xff0c;然后按【CtrlA】全部…

TCP 三次握手四次揮手

目錄 TCP 三次握手 1. SYN (Synchronize&#xff1a;同步) 2. SYN-ACK (Synchronize Acknowledge&#xff1a;同步確認) 3. ACK (Acknowledge&#xff1a;確認) 為什么是三次而不是兩次或四次&#xff1f; 三次握手的作用 TCP 四次揮手 第一次揮手&#xff1a;客戶端發送 FIN …

C語言初階牛客網刷題—— HJ34 圖片整理【難度:中等】

1. 題目描述 牛客網在線OJ鏈接 Lily上課時使用字母數字圖片教小朋友們學習英語單詞&#xff0c;每次都需要把這些圖片按照大小&#xff08;ASCII碼值從小到大&#xff09;排列收好。請大家給Lily幫忙&#xff0c;通過C語言解決。 輸入描述&#xff1a;Lily使用的圖片包括 “A…

MVCC底層原理實現

MVCC的實現原理 了解實現原理之前&#xff0c;先理解下面幾個組件的內容 1、 當前讀和快照讀 先普及一下什么是當前讀和快照讀。 當前讀&#xff1a;讀取數據的最新版本&#xff0c;并對數據進行加鎖。 例如&#xff1a;insert、update、delete、select for update、 sele…

python實現http文件服務器訪問下載

//1.py import http.server import socketserver import os import threading import sys# 獲取當前腳本所在的目錄 DIRECTORY os.path.dirname(os.path.abspath(__file__))# 設置服務器的端口 PORT 8000# 自定義Handler&#xff0c;將根目錄設置為腳本所在目錄 class MyHTT…

Cpp::靜態 動態的類型轉換全解析(36)

文章目錄 前言一、C語言中的類型轉換二、為什么C會有四種類型轉換&#xff1f;內置類型 -> 自定義類型自定義類型 -> 內置類型自定義類型 -> 自定義類型隱式類型轉換的坑 三、C強制類型轉換static_castreinterpret_castconst_castdynamic_cast 四、RTTI總結 前言 Hell…

2024年終總結:技術成長與突破之路

文章目錄 前言一、技術成長&#xff1a;菜鳥成長之路1. 學習與實踐的結合2. 技術分享與社區交流 二、生活與事業的平衡&#xff1a;技術之外的思考1. 時間管理與效率提升2. 技術對生活的積極影響 三、突破與展望&#xff1a;未來之路1. 技術領域的突破2. 未來規劃與目標 四、結…