欧美成人精品手机在线观看_69视频国产_动漫精品第一页_日韩中文字幕网 - 日本欧美一区二区

LOGO OA教程 ERP教程 模切知識交流 PMS教程 CRM教程 開發文檔 其他文檔  
 
網站管理員

10個常見的前端js手寫功能,你都會了嗎 ?

admin
2024年10月18日 23:32 本文熱度 583

#01 js防抖

在 JavaScript 中,防抖(debounce)是一種常用的優化技術,用于限制某個函數在一定時間內的觸發次數。

一、防抖的概念

當用戶進行某些頻繁觸發的操作時,比如滾動事件、輸入框的輸入事件等,如果直接綁定事件處理函數,可能會導致函數被頻繁調用,從而影響性能。防抖的目的就是在用戶操作停止一段時間后,才真正執行相應的函數,避免不必要的頻繁調用。

二、實現防抖的方法

以下是一個簡單的防抖函數的實現:

function debounce(func, delay) {let timer;return function() {const context = this;const args = arguments; ? ?clearTimeout(timer); ? ?timer = setTimeout(() => { ? ? ?func.apply(context, args); ? ?}, delay); ?};}

這個函數接受兩個參數:要執行的函數?func?和延遲時間?delay。它返回一個新的函數,當這個新函數被調用時,會先清除之前設置的定時器,然后重新設置一個定時器。如果在延遲時間內沒有再次調用這個新函數,定時器到期后就會執行原始函數。

三、使用防抖的示例

假設我們有一個輸入框,當用戶在輸入框中輸入內容時,我們希望在用戶停止輸入一段時間后才進行搜索操作。可以這樣使用防抖函數:

html:

<input type="text" id="searchInput">
js:
const input = document.getElementById('searchInput');function search() {console.log('Searching...');}input.addEventListener('input', debounce(search, 500));

在這個例子中,當用戶在輸入框中輸入內容時,debounce(search, 500)?返回的新函數會被觸發。如果用戶在 500 毫秒內沒有再次輸入,那么?search?函數就會被執行,進行搜索操作。如果用戶在 500 毫秒內繼續輸入,那么定時器會被清除,重新開始計時。

四、防抖的應用場景

  1. 搜索框輸入:如上述例子所示,避免在用戶輸入過程中頻繁進行搜索,提高性能。

  2. 窗口大小調整:當用戶調整窗口大小時,可能會觸發一些需要重新布局或計算的操作。使用防抖可以在用戶停止調整窗口一段時間后再執行這些操作,避免頻繁計算。

  3. 按鈕點擊:如果一個按鈕在短時間內可能被多次點擊,使用防抖可以確保只有在用戶停止點擊一段時間后才執行相應的操作,避免重復執行。


#02?js深拷貝

在 JavaScript 中,深拷貝是指創建一個對象的完全獨立的副本,包括對象的所有嵌套屬性和子對象。以下是關于 JavaScript 中深拷貝的詳細介紹:

一、為什么需要深拷貝

  1. 避免數據共享:當你有一個復雜的對象,并且希望對其進行修改而不影響原始對象時,深拷貝就非常有用。如果只是進行淺拷貝(例如使用賦值操作或?Object.assign()),修改副本可能會意外地修改原始對象,因為它們共享相同的嵌套對象引用。

  2. 數據獨立性:在某些情況下,你可能需要將一個對象傳遞給不同的部分代碼,并且確保這些部分代碼對該對象的修改不會相互影響。深拷貝可以提供這種數據獨立性。

二、實現深拷貝的方法

  1. 使用遞歸函數:

    • 可以編寫一個遞歸函數來遍歷對象的所有屬性,并對每個屬性進行深拷貝。如果屬性是基本類型(如字符串、數字、布爾值等),直接復制值。如果屬性是對象或數組,遞歸地調用深拷貝函數。

    • 以下是一個簡單的深拷貝函數的實現:

function deepCopy(obj) {if (obj === null || typeof obj!== 'object') {return obj; ? ? }let copy;if (Array.isArray(obj)) { ? ? ? copy = [];for (let i = 0; i < obj.length; i++) { ? ? ? ? copy[i] = deepCopy(obj[i]); ? ? ? } ? ? } else { ? ? ? copy = {};for (let key in obj) {if (obj.hasOwnProperty(key)) { ? ? ? ? ? copy[key] = deepCopy(obj[key]); ? ? ? ? } ? ? ? } ? ? }return copy; ? }
  1. 使用 JSON 序列化和反序列化:

    • 一種簡單的方法是將對象轉換為 JSON 字符串,然后再將其解析回對象。這種方法在大多數情況下都有效,但對于一些特殊類型的對象(如函數、正則表達式、日期對象等)可能會出現問題。

    • 示例代碼:

const originalObject = { a: 1, b: { c: 2 } };const copiedObject = JSON.parse(JSON.stringify(originalObject));

三、應用場景

  1. 對象克隆:當你需要創建一個與現有對象完全相同但獨立的副本時,可以使用深拷貝。例如,在某些數據處理場景中,你可能需要對一個對象進行多次操作,但又不想影響原始對象。

  2. 參數傳遞:在函數調用中,如果你希望傳遞一個對象的副本而不是原始對象,以避免函數內部的修改影響到外部的對象,可以使用深拷貝來傳遞參數。

  3. 數據持久化:當你需要將對象保存到本地存儲或數據庫時,通常需要進行深拷貝以確保保存的是對象的獨立副本,而不是對原始對象的引用。

總之,深拷貝在 JavaScript 中是一個重要的技術,用于創建對象的獨立副本,避免數據共享和意外的修改。在實際應用中,根據具體情況選擇合適的深拷貝方法可以提高代碼的可靠性和可維護性。

#03 js節流

在 JavaScript 中,節流(throttle)是一種用于控制函數執行頻率的技術,確保函數在特定時間間隔內最多執行一次。

一、節流的作用

  1. 性能優化:在一些頻繁觸發的事件中,如滾動事件、鼠標移動事件、窗口大小調整事件等,如果直接綁定事件處理函數,可能會導致函數被頻繁調用,從而占用大量的計算資源,影響性能。節流可以限制函數的執行頻率,減少不必要的計算,提高性能。

  2. 防止過度觸發:在某些情況下,我們希望函數在一定時間內只執行一次,即使事件被頻繁觸發。例如,在發送網絡請求時,我們可能希望在用戶輸入完成后再發送請求,而不是每次輸入都發送請求。節流可以幫助我們實現這種需求,防止函數被過度觸發。

二、節流的實現方法

  1. 使用時間戳和定時器:

    • 一種常見的實現節流的方法是使用時間戳和定時器。基本思路是記錄上一次執行函數的時間戳,當事件觸發時,判斷當前時間與上一次執行時間的差值是否大于指定的時間間隔。如果是,則執行函數,并更新上一次執行時間戳;如果不是,則不執行函數。如果在時間間隔內事件再次被觸發,設置一個定時器,在時間間隔結束后執行函數。

    • 以下是一個使用時間戳和定時器實現節流的示例代碼:

function throttle(func, delay) {let lastTime = 0;let timer = null;return function() {const now = Date.now();const context = this;const args = arguments;if (now - lastTime > delay) { ? ? ? ? func.apply(context, args); ? ? ? ? lastTime = now; ? ? ? } else if (!timer) { ? ? ? ? timer = setTimeout(() => { ? ? ? ? ? func.apply(context, args); ? ? ? ? ? timer = null; ? ? ? ? ? lastTime = Date.now(); ? ? ? ? }, delay); ? ? ? } ? ? }; ? }
  1. 使用定時器和標志位:

    • 另一種實現節流的方法是使用定時器和標志位。基本思路是設置一個標志位,表示函數是否正在執行。當事件觸發時,如果標志位為 false,則執行函數,并設置標志位為 true。在函數執行完成后,設置標志位為 false。如果在函數執行過程中事件再次被觸發,則不執行函數。為了確保函數在一定時間間隔內至少執行一次,可以使用定時器在時間間隔結束后執行函數,并重置標志位。

    • 以下是一個使用定時器和標志位實現節流的示例代碼:

function throttle(func, delay) {let isThrottled = false;let timer = null;return function() {const context = this;const args = arguments;if (!isThrottled) { ? ? ? ? func.apply(context, args); ? ? ? ? isThrottled = true; ? ? ? ? setTimeout(() => { ? ? ? ? ? isThrottled = false; ? ? ? ? }, delay); ? ? ? } else if (!timer) { ? ? ? ? timer = setTimeout(() => { ? ? ? ? ? func.apply(context, args); ? ? ? ? ? timer = null; ? ? ? ? }, delay); ? ? ? } ? ? }; ? }

三、節流的使用場景

  1. 滾動事件處理:在網頁滾動時,可能需要執行一些計算或更新操作。如果直接綁定滾動事件處理函數,可能會導致函數被頻繁調用,影響性能。使用節流可以限制函數在滾動事件中的執行頻率,提高性能。

    • 示例代碼:

window.addEventListener('scroll', throttle(function() {// 執行滾動事件處理函數 ? }, 200));
  1. 鼠標移動事件處理:在某些應用中,可能需要根據鼠標移動的位置進行實時計算或更新。使用節流可以限制函數在鼠標移動事件中的執行頻率,減少不必要的計算,提高性能。

    • 示例代碼:

document.addEventListener('mousemove', throttle(function(event) {// 執行鼠標移動事件處理函數 ? }, 50));
  1. 輸入框實時搜索:在輸入框中輸入內容時,可能需要實時搜索并顯示搜索結果。使用節流可以限制搜索函數的執行頻率,避免在用戶輸入過程中頻繁發送網絡請求,提高性能。

    • 示例代碼:

const input = document.getElementById('searchInput'); ? input.addEventListener('input', throttle(function() {const query = input.value;// 執行搜索函數 ? }, 300));

總之,節流是一種非常有用的技術,可以在 JavaScript 中控制函數的執行頻率,提高性能,防止過度觸發。在實際應用中,根據具體情況選擇合適的節流方法和時間間隔,可以有效地優化代碼的性能。

#04 js手寫Promise

以下是用 JavaScript 手寫一個簡單的 Promise:

class MyPromise {constructor(executor) {this.state = 'pending';this.value = undefined;this.reason = undefined;this.onFulfilledCallbacks = [];this.onRejectedCallbacks = [];
const resolve = (value) => {if (this.state === 'pending') {this.state = 'fulfilled';this.value = value;this.onFulfilledCallbacks.forEach((callback) => callback(this.value)); ? ? ?} ? ?};
const reject = (reason) => {if (this.state === 'pending') {this.state = 'rejected';this.reason = reason;this.onRejectedCallbacks.forEach((callback) => callback(this.reason)); ? ? ?} ? ?};
try { ? ? ?executor(resolve, reject); ? ?} catch (error) { ? ? ?reject(error); ? ?} ?}
?then(onFulfilled, onRejected) { ? ?onFulfilled = typeof onFulfilled === 'function'? onFulfilled : (value) => value; ? ?onRejected = typeof onRejected === 'function'? onRejected : (reason) => { throw reason; };
let promise2 = new MyPromise((resolve, reject) => {if (this.state === 'fulfilled') { ? ? ? ?setTimeout(() => {try {let x = onFulfilled(this.value); ? ? ? ? ? ?resolvePromise(promise2, x, resolve, reject); ? ? ? ? ?} catch (error) { ? ? ? ? ? ?reject(error); ? ? ? ? ?} ? ? ? ?}, 0); ? ? ?} else if (this.state === 'rejected') { ? ? ? ?setTimeout(() => {try {let x = onRejected(this.reason); ? ? ? ? ? ?resolvePromise(promise2, x, resolve, reject); ? ? ? ? ?} catch (error) { ? ? ? ? ? ?reject(error); ? ? ? ? ?} ? ? ? ?}, 0); ? ? ?} else {this.onFulfilledCallbacks.push((value) => { ? ? ? ? ?setTimeout(() => {try {let x = onFulfilled(value); ? ? ? ? ? ? ?resolvePromise(promise2, x, resolve, reject); ? ? ? ? ? ?} catch (error) { ? ? ? ? ? ? ?reject(error); ? ? ? ? ? ?} ? ? ? ? ?}, 0); ? ? ? ?});this.onRejectedCallbacks.push((reason) => { ? ? ? ? ?setTimeout(() => {try {let x = onRejected(reason); ? ? ? ? ? ? ?resolvePromise(promise2, x, resolve, reject); ? ? ? ? ? ?} catch (error) { ? ? ? ? ? ? ?reject(error); ? ? ? ? ? ?} ? ? ? ? ?}, 0); ? ? ? ?}); ? ? ?} ? ?});
return promise2; ?}
catch(onRejected) {return this.then(null, onRejected); ?}}
function resolvePromise(promise2, x, resolve, reject) {if (promise2 === x) {return reject(new TypeError('Chaining cycle detected for promise')); ?}let called = false;if (x instanceof MyPromise) { ? ?x.then((y) => { ? ? ?resolvePromise(promise2, y, resolve, reject); ? ?}, reject); ?} else if (x!== null && (typeof x === 'object' || typeof x === 'function')) {try {let then = x.then;if (typeof then === 'function') { ? ? ? ?then.call(x, (y) => {if (called) return; ? ? ? ? ?called = true; ? ? ? ? ?resolvePromise(promise2, y, resolve, reject); ? ? ? ?}, (r) => {if (called) return; ? ? ? ? ?called = true; ? ? ? ? ?reject(r); ? ? ? ?}); ? ? ?} else { ? ? ? ?resolve(x); ? ? ?} ? ?} catch (e) {if (called) return; ? ? ?called = true; ? ? ?reject(e); ? ?} ?} else { ? ?resolve(x); ?}}

你可以使用這個自定義的 Promise 如下:

let myPromise = new MyPromise((resolve, reject) => { ?setTimeout(() => { ? ?resolve('Success!'); ?}, 1000);});
myPromise.then((value) => {console.log(value);return 'Another value';}).then((value) => {console.log(value);});

這個實現雖然簡單,但涵蓋了 Promise 的基本功能,包括異步執行、狀態轉換和鏈式調用。在實際應用中,可能需要進一步擴展和優化這個實現以滿足更復雜的需求。

#05 js 異步控制并發數

在 JavaScript 中,可以通過多種方式來控制異步操作的并發數。以下是一種常見的實現方法:

function asyncFunctionWithConcurrencyLimit(asyncFunctions, concurrencyLimit) {let inFlightCount = 0;let results = [];let index = 0;
function executeNext() {if (index < asyncFunctions.length && inFlightCount < concurrencyLimit) { ? ? ?inFlightCount++;const currentIndex = index; ? ? ?index++;const asyncFunc = asyncFunctions[currentIndex]; ? ? ?asyncFunc().then((result) => { ? ? ? ?results[currentIndex] = result; ? ? ? ?inFlightCount--; ? ? ? ?executeNext(); ? ? ?}).catch((error) => { ? ? ? ?results[currentIndex] = error; ? ? ? ?inFlightCount--; ? ? ? ?executeNext(); ? ? ?}); ? ?} ?}
for (let i = 0; i < concurrencyLimit && i < asyncFunctions.length; i++) { ? ?executeNext(); ?}
return new Promise((resolve, reject) => {const interval = setInterval(() => {if (results.length === asyncFunctions.length) { ? ? ? ?clearInterval(interval); ? ? ? ?resolve(results); ? ? ?} ? ?}, 100); ?});}

使用方法如下:

// 模擬一些異步函數function asyncTask(index) {return new Promise((resolve, reject) => { ? ?setTimeout(() => { ? ? ?resolve(`Task ${index} completed`); ? ?}, Math.random() * 2000); ?});}});
const tasks = Array.from({ length: 10 }, (_, index) => asyncTask(index));const concurrencyLimit = 3;
asyncFunctionWithConcurrencyLimit(tasks, concurrencyLimit).then((results) => {console.log(results);

在這個例子中,asyncFunctionWithConcurrencyLimit?函數接受一個異步函數數組和一個并發數限制作為參數。它通過控制同時執行的異步函數數量來確保不會超出并發限制。當一個異步函數完成時,會自動啟動下一個異步函數,直到所有的異步函數都完成。最后,它返回一個 Promise,當所有異步函數都完成時,這個 Promise 會被 resolve,結果數組包含了所有異步函數的執行結果。

#06 js繼承

在 JavaScript 中,實現繼承有多種方式。以下是幾種常見的方法:

一、原型鏈繼承

  1. 基本原理:

    • JavaScript 對象有一個指向其原型對象的內部鏈接。通過讓一個對象的原型指向另一個對象,可以實現繼承。

    • 子類型的原型對象是父類型的一個實例,這樣子類型就可以訪問父類型的屬性和方法。

  2. 示例代碼:

function Parent() { ? ? this.parentProperty = 'parent value'; ? } ? Parent.prototype.parentMethod = function() { ? ? console.log('This is a parent method.'); ? }; ? function Child() {} ? Child.prototype = new Parent(); ? const child = new Child(); ? console.log(child.parentProperty); // 'parent value' ? child.parentMethod(); // 'This is a parent method.'
  1. 優缺點:

    • 優點:實現簡單,可以繼承父類的原型屬性和方法。

    • 缺點:多個實例對引用類型的原型屬性的修改會相互影響;無法向父類構造函數傳參。

二、構造函數繼承

  1. 基本原理:

    • 在子類型的構造函數中調用父類型的構造函數,并使用?call?或?apply?方法改變?this?的指向,將父類型的屬性和方法復制到子類型的實例上。

  2. 示例代碼:

function Parent(name) { ? ? this.parentProperty = 'parent value'; ? ? this.name = name; ? } ? function Child(name) { ? ? Parent.call(this, name); ? ? this.childProperty = 'child value'; ? } ? const child = new Child('child name'); ? console.log(child.parentProperty); // 'parent value' ? console.log(child.name); // 'child name'
  1. 優缺點:

    • 優點:可以向父類構造函數傳參;避免了多個實例對引用類型的原型屬性的修改相互影響。

    • 缺點:只能繼承父類的實例屬性和方法,不能繼承父類的原型屬性和方法。

三、組合繼承

  1. 基本原理:

    • 結合原型鏈繼承和構造函數繼承的優點,通過在子類型的構造函數中調用父類型的構造函數來繼承實例屬性,同時讓子類型的原型對象指向父類型的實例來繼承原型屬性和方法。

  2. 示例代碼:

function Parent(name) { ? ? this.parentProperty = 'parent value'; ? ? this.name = name; ? } ? Parent.prototype.parentMethod = function() { ? ? console.log('This is a parent method.'); ? }; ? function Child(name) { ? ? Parent.call(this, name); ? ? this.childProperty = 'child value'; ? } ? Child.prototype = new Parent(); ? Child.prototype.constructor = Child; ? const child = new Child('child name'); ? console.log(child.parentProperty); // 'parent value' ? console.log(child.name); // 'child name'???child.parentMethod();?//?'This?is?a?parent?method.
  1. 優缺點:

    • 優點:可以繼承父類的實例屬性和方法,也可以繼承父類的原型屬性和方法;可以向父類構造函數傳參;避免了多個實例對引用類型的原型屬性的修改相互影響。

    • 缺點:調用了兩次父類構造函數,可能會影響性能。

四、寄生組合式繼承

  1. 基本原理:

    • 避免組合繼承中調用兩次父類構造函數的問題,通過創建一個中間函數來繼承父類的原型屬性和方法,然后將這個中間函數的實例賦值給子類型的原型對象。

  2. 示例代碼:

 function inheritPrototype(child, parent) { ? ? const prototype = Object.create(parent.prototype); ? ? prototype.constructor = child; ? ? child.prototype = prototype; ? } ? function Parent(name) { ? ? this.parentProperty = 'parent value'; ? ? this.name = name; ? } ? Parent.prototype.parentMethod = function() { ? ? console.log('This is a parent method.'); ? }; ? function Child(name) { ? ? Parent.call(this, name); ? ? this.childProperty = 'child value'; ? } ? inheritPrototype(Child, Parent); ? const child = new Child('child name'); ? console.log(child.parentProperty); // 'parent value' ? console.log(child.name); // 'child name' ? child.parentMethod(); // 'This is a parent method.'
  1. 優缺點:

    • 優點:只調用了一次父類構造函數,性能較好;可以繼承父類的實例屬性和方法,也可以繼承父類的原型屬性和方法;可以向父類構造函數傳參;避免了多個實例對引用類型的原型屬性的修改相互影響。

總之,JavaScript 中的繼承方式各有優缺點,開發者可以根據實際情況選擇合適的繼承方式。

#07 js數組排序

在 JavaScript 中,可以使用數組的?sort?方法對數組進行排序。sort?方法會對數組進行原地排序,即直接修改原數組。

一、基本排序

  1. 升序排序:

    • 如果不提供比較函數,sort?方法會將數組元素轉換為字符串,然后按照字典序進行升序排序。對于數字數組,這可能不是期望的結果。

    • 示例代碼:

 const numbers = [4, 2, 5, 1, 3]; ? const sortedNumbers = numbers.sort(); ? console.log(sortedNumbers); // [1, 2, 3, 4, 5]
  1. 降序排序:

    • 可以通過提供一個比較函數來實現降序排序。比較函數接收兩個參數,如果第一個參數應該排在第二個參數之前,則返回一個負數;如果兩個參數相等,則返回 0;如果第一個參數應該排在第二個參數之后,則返回一個正數。

    • 示例代碼:

 const numbers = [4, 2, 5, 1, 3]; ? const sortedNumbers = numbers.sort((a, b) => b - a); ? console.log(sortedNumbers); // [5, 4, 3, 2, 1]

二、對象數組排序

  1. 根據對象屬性排序:

    • 對于包含對象的數組,可以根據對象的某個屬性進行排序。

    • 示例代碼:

 const people = [ ? ? { name: 'Alice', age: 30 }, ? ? { name: 'Bob', age: 25 }, ? ? { name: 'Charlie', age: 35 } ? ]; ? const sortedPeople = people.sort((a, b) => a.age - b.age); ? console.log(sortedPeople); ? // [ ? // ? { name: 'Bob', age: 25 }, ? // ? { name: 'Alice', age: 30 }, ? // ? { name: 'Charlie', age: 35 } ? // ]
  1. 多個屬性排序:

    • 如果需要根據多個屬性進行排序,可以在比較函數中依次比較這些屬性。

    • 示例代碼:

const people = [ ? ? { name: 'Alice', age: 30 }, ? ? { name: 'Bob', age: 25 }, ? ? { name: 'Charlie', age: 30 }, ? ? { name: 'David', age: 25 } ? ]; ? const sortedPeople = people.sort((a, b) => { ? ? if (a.age!== b.age) { ? ? ? return a.age - b.age; ? ? } else { ? ? ? return a.name.localeCompare(b.name); ? ? } ? }); ? console.log(sortedPeople); ? // [ ? // ? { name: 'Bob', age: 25 }, ? // ? { name: 'David', age: 25 }, ? // ? { name: 'Alice', age: 30 }, ? // ? { name: 'Charlie', age: 30 } ? // ]

三、穩定性

  1. 穩定性的重要性:

    • 排序算法的穩定性是指在排序過程中,如果兩個元素相等,它們在排序后的相對位置與排序前保持一致。在某些情況下,穩定性是很重要的,例如當需要對已經按照某個屬性排序的數組再按照另一個屬性排序時。

  2. JavaScript 的?sort?方法的穩定性:

    • JavaScript 的?sort?方法在默認情況下是穩定的,即當比較函數返回 0 時,兩個元素的相對位置不會改變。

四、自定義比較函數

  1. 靈活的比較邏輯:

    • 可以根據具體的需求編寫自定義的比較函數,實現各種復雜的排序邏輯。

    • 示例代碼:

const fruits = ['apple', 'banana', 'cherry', 'date']; ? const sortedFruits = fruits.sort((a, b) => { ? ? if (a.length!== b.length) { ? ? ? return a.length - b.length; ? ? } else { ? ? ? return a.localeCompare(b); ? ? } ? }); ? console.log(sortedFruits); ? // ['date', 'apple', 'cherry', 'banana']
  1. 處理不同類型的數據:

    • 比較函數可以處理不同類型的數據,例如數字、字符串、對象等。在比較不同類型的數據時,需要根據具體情況進行適當的類型轉換和比較。

JavaScript 的數組排序功能非常強大,可以通過簡單的方式實現各種排序需求。在使用?sort?方法時,需要注意比較函數的返回值規則,以確保得到正確的排序結果。同時,根據具體情況選擇合適的排序算法和比較函數,可以提高排序的效率和穩定性。

#08?js 數組去重

在 JavaScript 中,可以通過以下幾種方法實現數組去重:

一、使用 ES6 的 Set 和擴展運算符

  1. 基本原理:

    • Set 是 ES6 新增的數據結構,它類似于數組,但成員的值都是唯一的。

    • 可以將數組轉換為 Set,然后再轉換回數組,利用 Set 的唯一性實現去重。

  2. 示例代碼:

 const arr = [1, 2, 2, 3, 4, 4, 5]; ? const uniqueArr = [...new Set(arr)];???console.log(uniqueArr);?//?[1,?2,?3,?4,?5]

二、使用 for 循環和 indexOf

  1. 基本原理:

    • 遍歷數組元素,對于每個元素,檢查它在新數組中是否已經存在。如果不存在,則將其添加到新數組中。

  2. 示例代碼:

const arr = [1, 2, 2, 3, 4, 4, 5]; ? const uniqueArr = []; ? for (let i = 0; i < arr.length; i++) { ? ? if (uniqueArr.indexOf(arr[i]) === -1) { ? ? ? uniqueArr.push(arr[i]); ? ? } ? } ? console.log(uniqueArr); // [1, 2, 3, 4, 5]

三、使用 forEach 和 includes

  1. 基本原理:

    • 與使用 for 循環和 indexOf 的方法類似,但是使用?forEach?方法遍歷數組,使用?includes?方法檢查元素是否在新數組中。

  2. 示例代碼:

const arr = [1, 2, 2, 3, 4, 4, 5]; ? const uniqueArr = []; ? arr.forEach(item => { ? ? if (!uniqueArr.includes(item)) { ? ? ? uniqueArr.push(item); ? ? } ? }); ? console.log(uniqueArr); // [1, 2, 3, 4, 5]

四、使用 reduce

  1. 基本原理:

    • reduce?是數組的一種高階函數,它可以對數組中的每個元素進行累積操作。

    • 可以使用?reduce?方法遍歷數組,將不重復的元素添加到累積器中。

  2. 示例代碼:

 const arr = [1, 2, 2, 3, 4, 4, 5]; ? const uniqueArr = arr.reduce((acc, item) => { ? ? if (!acc.includes(item)) { ? ? ? acc.push(item); ? ? } ? ? return acc; ? }, []); ? console.log(uniqueArr); // [1, 2, 3, 4, 5]

五、對象屬性法

  1. 基本原理:

    • 創建一個空對象,將數組元素作為對象的屬性名,如果屬性不存在,則將元素添加到新數組中。

  2. 示例代碼:

const arr = [1, 2, 2, 3, 4, 4, 5]; ? const uniqueArr = []; ? const temp = {}; ? arr.forEach(item => { ? ? if (!temp[item]) { ? ? ? temp[item] = true; ? ? ? uniqueArr.push(item); ? ? } ? }); ? console.log(uniqueArr); // [1, 2, 3, 4, 5]

這些方法各有優缺點,可以根據具體情況選擇合適的方法。例如,使用 Set 和擴展運算符的方法簡潔高效,但不支持在低版本的瀏覽器中使用;使用 for 循環和 indexOf 的方法兼容性好,但代碼相對較長。

#09?js 獲取URL參數

在 JavaScript 中,可以通過以下幾種方式獲取 URL 中的參數:

一、使用正則表達式

  1. 基本原理:

    • 通過正則表達式匹配 URL 中的參數部分,然后解析出各個參數的值。

  2. 示例代碼:

function getUrlParams(url) { ? ? const params = {}; ? ? const regex = /[?&]([^=#]+)=([^&#]*)/g; ? ? let match; ? ? while ((match = regex.exec(url))!== null) { ? ? ? params[match[1]] = decodeURIComponent(match[2]); ? ? } ? ? return params; ? } ? const url = 'https://example.com/page?param1=value1¶m2=value2'; ? const params = getUrlParams(url); ? console.log(params); // {param1: "value1", param2: "value2"}

二、使用 URLSearchParams API

  1. 基本原理:

    • URLSearchParams是一個內置的 JavaScript API,它提供了一種方便的方式來處理 URL 查詢參數。

  2. 示例代碼:

const url = 'https://example.com/page?param1=value1¶m2=value2'; ? const urlParams = new URLSearchParams(url.split('?')[1]); ? const params = {}; ? for (const [key, value] of urlParams.entries()) { ? ? params[key] = value; ? } ? console.log(params); // {param1: "value1", param2: "value2"}

三、手動解析 URL

  1. 基本原理:

    • 首先獲取 URL 的查詢部分,然后通過分割字符串的方式解析出各個參數的值。

  2. 示例代碼:

function getUrlParams(url) { ? ? const params = {}; ? ? const queryString = url.split('?')[1]; ? ? if (!queryString) return params; ? ? const pairs = queryString.split('&'); ? ? for (let i = 0; i < pairs.length; i++) { ? ? ? const pair = pairs[i].split('='); ? ? ? const key = decodeURIComponent(pair[0]); ? ? ? const value = decodeURIComponent(pair[1]); ? ? ? params[key] = value; ? ? } ? ? return params; ? } ? const url = 'https://example.com/page?param1=value1¶m2=value2'; ? const params = getUrlParams(url); ? console.log(params); // {param1: "value1", param2: "value2"}

這些方法可以根據具體的需求和環境選擇使用。如果瀏覽器支持URLSearchParams?API,那么使用它是一種比較簡潔和現代的方式。如果需要兼容舊版本的瀏覽器,可以使用正則表達式或手動解析 URL 的方法。

#10 js發布訂閱模式

在 JavaScript 中,發布訂閱模式是一種常用的設計模式,它允許對象之間進行松耦合的通信。在發布訂閱模式中,有三個主要的角色:發布者、訂閱者和事件中心。

一、發布訂閱模式的概念

  1. 發布者(Publisher):發布者是產生事件的對象。當發布者發生某些事件時,它會通知事件中心。

  2. 訂閱者(Subscriber):訂閱者是對特定事件感興趣的對象。訂閱者向事件中心注冊自己,以便在特定事件發生時得到通知。

  3. 事件中心(Event Center):事件中心是發布者和訂閱者之間的中介。它負責管理事件的訂閱和發布,當發布者發布事件時,事件中心會通知所有訂閱了該事件的訂閱者。

二、發布訂閱模式的實現

  1. 使用對象實現:

    • 可以使用一個普通的對象來實現事件中心。這個對象有一些方法,用于訂閱事件、發布事件和取消訂閱事件。

    • 以下是一個使用對象實現發布訂閱模式的示例代碼:

const eventCenter = { ? ? events: {}, ? ? subscribe(eventName, callback) { ? ? ? if (!this.events[eventName]) { ? ? ? ? this.events[eventName] = []; ? ? ? } ? ? ? this.events[eventName].push(callback); ? ? }, ? ? publish(eventName, data) { ? ? ? if (this.events[eventName]) { ? ? ? ? this.events[eventName].forEach(callback => callback(data)); ? ? ? } ? ? }, ? ? unsubscribe(eventName, callback) { ? ? ? if (this.events[eventName]) { ? ? ? ? this.events[eventName] = this.events[eventName].filter(cb => cb!== callback); ? ? ? } ? ? } ? };
  1. 使用類實現:

    • 也可以使用一個類來實現事件中心。這個類有一些方法,用于訂閱事件、發布事件和取消訂閱事件。

    • 以下是一個使用類實現發布訂閱模式的示例代碼:

class EventEmitter { ? ? constructor() { ? ? ? this.events = {}; ? ? } ? ? subscribe(eventName, callback) { ? ? ? if (!this.events[eventName]) { ? ? ? ? this.events[eventName] = []; ? ? ? } ? ? ? this.events[eventName].push(callback); ? ? } ? ? publish(eventName, data) { ? ? ? if (this.events[eventName]) { ? ? ? ? this.events[eventName].forEach(callback => callback(data)); ? ? ? } ? ? } ? ? unsubscribe(eventName, callback) { ? ? ? if (this.events[eventName]) { ? ? ? ? this.events[eventName] = this.events[eventName].filter(cb => cb!== callback); ? ? ? } ? ? } ? }

三、發布訂閱模式的使用

  1. 訂閱事件:

    • 訂閱者可以使用事件中心的?subscribe?方法來訂閱特定的事件。當事件發生時,事件中心會調用訂閱者提供的回調函數。

    • 以下是一個訂閱事件的示例代碼:

ventCenter.subscribe('eventName', (data) => { ? ? console.log(`Received event "${eventName}" with data: ${data}`); ? });
  • 發布事件:

    • 發布者可以使用事件中心的?publish?方法來發布事件。事件中心會通知所有訂閱了該事件的訂閱者。

    • 以下是一個發布事件的示例代碼:

 ? eventCenter.publish('eventName', 'event data');
  1. 取消訂閱事件:

    • 訂閱者可以使用事件中心的?unsubscribe?方法來取消訂閱特定的事件。

    • 以下是一個取消訂閱事件的示例代碼:

const callback = (data) => { ? ? console.log(`Received event "${eventName}" with data: ${data}`); ? }; ? eventCenter.subscribe('eventName', callback); ? eventCenter.unsubscribe('eventName', callback);

四、發布訂閱模式的優點

  1. 松耦合:發布者和訂閱者之間沒有直接的依賴關系,它們通過事件中心進行通信。這使得代碼更加靈活和可維護。

  2. 可擴展性:可以輕松地添加新的發布者和訂閱者,而不會影響現有的代碼。

  3. 事件驅動:發布訂閱模式是一種事件驅動的編程方式,它可以更好地處理異步操作和并發事件。

五、發布訂閱模式的缺點

  1. 內存管理:如果訂閱者沒有正確地取消訂閱事件,可能會導致內存泄漏。

  2. 調試困難:由于發布者和訂閱者之間沒有直接的調用關系,調試起來可能會比較困難。


發布訂閱模式是一種非常有用的設計模式,它可以幫助你實現松耦合的通信,提高代碼的可維護性和可擴展性。在使用發布訂閱模式時,需要注意內存管理和調試問題,以確保代碼的正確性和性能。


該文章在 2024/10/19 12:40:37 編輯過
關鍵字查詢
相關文章
正在查詢...
點晴ERP是一款針對中小制造業的專業生產管理軟件系統,系統成熟度和易用性得到了國內大量中小企業的青睞。
點晴PMS碼頭管理系統主要針對港口碼頭集裝箱與散貨日常運作、調度、堆場、車隊、財務費用、相關報表等業務管理,結合碼頭的業務特點,圍繞調度、堆場作業而開發的。集技術的先進性、管理的有效性于一體,是物流碼頭及其他港口類企業的高效ERP管理信息系統。
點晴WMS倉儲管理系統提供了貨物產品管理,銷售管理,采購管理,倉儲管理,倉庫管理,保質期管理,貨位管理,庫位管理,生產管理,WMS管理系統,標簽打印,條形碼,二維碼管理,批號管理軟件。
點晴免費OA是一款軟件和通用服務都免費,不限功能、不限時間、不限用戶的免費OA協同辦公管理系統。
Copyright 2010-2025 ClickSun All Rights Reserved