LOGO OA教程 ERP教程 模切知識交流 PMS教程 CRM教程 開發(fā)文檔 其他文檔  
 
網(wǎng)站管理員

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

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

#01 js防抖

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

一、防抖的概念

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

二、實現(xiàn)防抖的方法

以下是一個簡單的防抖函數(shù)的實現(xiàn):

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

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

三、使用防抖的示例

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

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)?返回的新函數(shù)會被觸發(fā)。如果用戶在 500 毫秒內沒有再次輸入,那么?search?函數(shù)就會被執(zhí)行,進行搜索操作。如果用戶在 500 毫秒內繼續(xù)輸入,那么定時器會被清除,重新開始計時。

四、防抖的應用場景

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

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

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


#02?js深拷貝

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

一、為什么需要深拷貝

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

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

二、實現(xiàn)深拷貝的方法

  1. 使用遞歸函數(shù):

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

    • 以下是一個簡單的深拷貝函數(shù)的實現(xiàn):

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 字符串,然后再將其解析回對象。這種方法在大多數(shù)情況下都有效,但對于一些特殊類型的對象(如函數(shù)、正則表達式、日期對象等)可能會出現(xiàn)問題。

    • 示例代碼:

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

三、應用場景

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

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

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

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

#03 js節(jié)流

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

一、節(jié)流的作用

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

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

二、節(jié)流的實現(xiàn)方法

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

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

    • 以下是一個使用時間戳和定時器實現(xiàn)節(jié)流的示例代碼:

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. 使用定時器和標志位:

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

    • 以下是一個使用定時器和標志位實現(xiàn)節(jié)流的示例代碼:

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); ? ? ? } ? ? }; ? }

三、節(jié)流的使用場景

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

    • 示例代碼:

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

    • 示例代碼:

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

    • 示例代碼:

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

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

#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);});

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

#05 js 異步控制并發(fā)數(shù)

在 JavaScript 中,可以通過多種方式來控制異步操作的并發(fā)數(shù)。以下是一種常見的實現(xiàn)方法:

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); ?});}

使用方法如下:

// 模擬一些異步函數(shù)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?函數(shù)接受一個異步函數(shù)數(shù)組和一個并發(fā)數(shù)限制作為參數(shù)。它通過控制同時執(zhí)行的異步函數(shù)數(shù)量來確保不會超出并發(fā)限制。當一個異步函數(shù)完成時,會自動啟動下一個異步函數(shù),直到所有的異步函數(shù)都完成。最后,它返回一個 Promise,當所有異步函數(shù)都完成時,這個 Promise 會被 resolve,結果數(shù)組包含了所有異步函數(shù)的執(zhí)行結果。

#06 js繼承

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

一、原型鏈繼承

  1. 基本原理:

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

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

  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. 優(yōu)缺點:

    • 優(yōu)點:實現(xiàn)簡單,可以繼承父類的原型屬性和方法。

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

二、構造函數(shù)繼承

  1. 基本原理:

    • 在子類型的構造函數(shù)中調用父類型的構造函數(shù),并使用?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. 優(yōu)缺點:

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

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

三、組合繼承

  1. 基本原理:

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

  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. 優(yōu)缺點:

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

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

四、寄生組合式繼承

  1. 基本原理:

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

  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. 優(yōu)缺點:

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

總之,JavaScript 中的繼承方式各有優(yōu)缺點,開發(fā)者可以根據(jù)實際情況選擇合適的繼承方式。

#07 js數(shù)組排序

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

一、基本排序

  1. 升序排序:

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

    • 示例代碼:

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

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

    • 示例代碼:

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

二、對象數(shù)組排序

  1. 根據(jù)對象屬性排序:

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

    • 示例代碼:

 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. 多個屬性排序:

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

    • 示例代碼:

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 } ? // ]

三、穩(wěn)定性

  1. 穩(wěn)定性的重要性:

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

  2. JavaScript 的?sort?方法的穩(wěn)定性:

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

四、自定義比較函數(shù)

  1. 靈活的比較邏輯:

    • 可以根據(jù)具體的需求編寫自定義的比較函數(shù),實現(xiàn)各種復雜的排序邏輯。

    • 示例代碼:

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. 處理不同類型的數(shù)據(jù):

    • 比較函數(shù)可以處理不同類型的數(shù)據(jù),例如數(shù)字、字符串、對象等。在比較不同類型的數(shù)據(jù)時,需要根據(jù)具體情況進行適當?shù)念愋娃D換和比較。

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

#08?js 數(shù)組去重

在 JavaScript 中,可以通過以下幾種方法實現(xiàn)數(shù)組去重:

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

  1. 基本原理:

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

    • 可以將數(shù)組轉換為 Set,然后再轉換回數(shù)組,利用 Set 的唯一性實現(xiàn)去重。

  2. 示例代碼:

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

二、使用 for 循環(huán)和 indexOf

  1. 基本原理:

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

  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 循環(huán)和 indexOf 的方法類似,但是使用?forEach?方法遍歷數(shù)組,使用?includes?方法檢查元素是否在新數(shù)組中。

  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?是數(shù)組的一種高階函數(shù),它可以對數(shù)組中的每個元素進行累積操作。

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

  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. 基本原理:

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

  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]

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

#09?js 獲取URL參數(shù)

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

一、使用正則表達式

  1. 基本原理:

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

  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 查詢參數(shù)。

  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 的查詢部分,然后通過分割字符串的方式解析出各個參數(shù)的值。

  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"}

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

#10 js發(fā)布訂閱模式

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

一、發(fā)布訂閱模式的概念

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

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

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

二、發(fā)布訂閱模式的實現(xiàn)

  1. 使用對象實現(xiàn):

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

    • 以下是一個使用對象實現(xiàn)發(fā)布訂閱模式的示例代碼:

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. 使用類實現(xiàn):

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

    • 以下是一個使用類實現(xiàn)發(fā)布訂閱模式的示例代碼:

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); ? ? ? } ? ? } ? }

三、發(fā)布訂閱模式的使用

  1. 訂閱事件:

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

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

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

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

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

 ? 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);

四、發(fā)布訂閱模式的優(yōu)點

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

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

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

五、發(fā)布訂閱模式的缺點

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

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


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


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

黄频国产免费高清视频,久久不卡精品中文字幕一区,激情五月天AV电影在线观看,欧美国产韩国日本一区二区
中文字幕日韩一区二区不卡 | 亚洲精品福利在线视频 | 亚洲欧美日韩精品一区二区 | 综合在线视频精品专区 | 久久精品免费观看全 | 三级视频欧美不卡在线观看 |