狠狠色丁香婷婷综合尤物/久久精品综合一区二区三区/中国有色金属学报/国产日韩欧美在线观看 - 国产一区二区三区四区五区tv

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

10個(gè)常見的前端js手寫功能,你都會(huì)了嗎 ?

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

#01 js防抖

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

一、防抖的概念

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

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

以下是一個(gè)簡(jiǎn)單的防抖函數(shù)的實(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); ?};}

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

三、使用防抖的示例

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

html:

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

在這個(gè)例子中,當(dāng)用戶在輸入框中輸入內(nèi)容時(shí),debounce(search, 500)?返回的新函數(shù)會(huì)被觸發(fā)。如果用戶在 500 毫秒內(nèi)沒有再次輸入,那么?search?函數(shù)就會(huì)被執(zhí)行,進(jìn)行搜索操作。如果用戶在 500 毫秒內(nèi)繼續(xù)輸入,那么定時(shí)器會(huì)被清除,重新開始計(jì)時(shí)。

四、防抖的應(yīng)用場(chǎng)景

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

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

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


#02?js深拷貝

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

一、為什么需要深拷貝

  1. 避免數(shù)據(jù)共享:當(dāng)你有一個(gè)復(fù)雜的對(duì)象,并且希望對(duì)其進(jìn)行修改而不影響原始對(duì)象時(shí),深拷貝就非常有用。如果只是進(jìn)行淺拷貝(例如使用賦值操作或?Object.assign()),修改副本可能會(huì)意外地修改原始對(duì)象,因?yàn)樗鼈児蚕硐嗤那短讓?duì)象引用。

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

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

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

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

    • 以下是一個(gè)簡(jiǎn)單的深拷貝函數(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 序列化和反序列化:

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

    • 示例代碼:

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

三、應(yīng)用場(chǎng)景

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

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

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

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

#03 js節(jié)流

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

一、節(jié)流的作用

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

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

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

  1. 使用時(shí)間戳和定時(shí)器:

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

    • 以下是一個(gè)使用時(shí)間戳和定時(shí)器實(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. 使用定時(shí)器和標(biāo)志位:

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

    • 以下是一個(gè)使用定時(shí)器和標(biāo)志位實(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é)流的使用場(chǎng)景

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

    • 示例代碼:

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

    • 示例代碼:

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

    • 示例代碼:

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

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

#04 js手寫Promise

以下是用 JavaScript 手寫一個(gè)簡(jiǎn)單的 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); ?}}

你可以使用這個(gè)自定義的 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);});

這個(gè)實(shí)現(xiàn)雖然簡(jiǎn)單,但涵蓋了 Promise 的基本功能,包括異步執(zhí)行、狀態(tài)轉(zhuǎn)換和鏈?zhǔn)秸{(diào)用。在實(shí)際應(yīng)用中,可能需要進(jìn)一步擴(kuò)展和優(yōu)化這個(gè)實(shí)現(xiàn)以滿足更復(fù)雜的需求。

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

在 JavaScript 中,可以通過多種方式來控制異步操作的并發(fā)數(shù)。以下是一種常見的實(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);

在這個(gè)例子中,asyncFunctionWithConcurrencyLimit?函數(shù)接受一個(gè)異步函數(shù)數(shù)組和一個(gè)并發(fā)數(shù)限制作為參數(shù)。它通過控制同時(shí)執(zhí)行的異步函數(shù)數(shù)量來確保不會(huì)超出并發(fā)限制。當(dāng)一個(gè)異步函數(shù)完成時(shí),會(huì)自動(dòng)啟動(dòng)下一個(gè)異步函數(shù),直到所有的異步函數(shù)都完成。最后,它返回一個(gè) Promise,當(dāng)所有異步函數(shù)都完成時(shí),這個(gè) Promise 會(huì)被 resolve,結(jié)果數(shù)組包含了所有異步函數(shù)的執(zhí)行結(jié)果。

#06 js繼承

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

一、原型鏈繼承

  1. 基本原理:

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

    • 子類型的原型對(duì)象是父類型的一個(gè)實(shí)例,這樣子類型就可以訪問父類型的屬性和方法。

  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)缺點(diǎn):

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

    • 缺點(diǎn):多個(gè)實(shí)例對(duì)引用類型的原型屬性的修改會(huì)相互影響;無法向父類構(gòu)造函數(shù)傳參。

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

  1. 基本原理:

    • 在子類型的構(gòu)造函數(shù)中調(diào)用父類型的構(gòu)造函數(shù),并使用?call?或?apply?方法改變?this?的指向,將父類型的屬性和方法復(fù)制到子類型的實(shí)例上。

  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)缺點(diǎn):

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

    • 缺點(diǎn):只能繼承父類的實(shí)例屬性和方法,不能繼承父類的原型屬性和方法。

三、組合繼承

  1. 基本原理:

    • 結(jié)合原型鏈繼承和構(gòu)造函數(shù)繼承的優(yōu)點(diǎn),通過在子類型的構(gòu)造函數(shù)中調(diào)用父類型的構(gòu)造函數(shù)來繼承實(shí)例屬性,同時(shí)讓子類型的原型對(duì)象指向父類型的實(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)缺點(diǎn):

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

    • 缺點(diǎn):調(diào)用了兩次父類構(gòu)造函數(shù),可能會(huì)影響性能。

四、寄生組合式繼承

  1. 基本原理:

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

  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)缺點(diǎn):

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

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

#07 js數(shù)組排序

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

一、基本排序

  1. 升序排序:

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

    • 示例代碼:

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

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

    • 示例代碼:

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

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

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

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

    • 示例代碼:

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

    • 如果需要根據(jù)多個(gè)屬性進(jìn)行排序,可以在比較函數(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)定性是指在排序過程中,如果兩個(gè)元素相等,它們?cè)谂判蚝蟮南鄬?duì)位置與排序前保持一致。在某些情況下,穩(wěn)定性是很重要的,例如當(dāng)需要對(duì)已經(jīng)按照某個(gè)屬性排序的數(shù)組再按照另一個(gè)屬性排序時(shí)。

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

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

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

  1. 靈活的比較邏輯:

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

    • 示例代碼:

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ù)字、字符串、對(duì)象等。在比較不同類型的數(shù)據(jù)時(shí),需要根據(jù)具體情況進(jìn)行適當(dāng)?shù)念愋娃D(zhuǎn)換和比較。

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

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

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

一、使用 ES6 的 Set 和擴(kuò)展運(yùn)算符

  1. 基本原理:

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

    • 可以將數(shù)組轉(zhuǎn)換為 Set,然后再轉(zhuǎn)換回?cái)?shù)組,利用 Set 的唯一性實(shí)現(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ù)組元素,對(duì)于每個(gè)元素,檢查它在新數(shù)組中是否已經(jīng)存在。如果不存在,則將其添加到新數(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ù),它可以對(duì)數(shù)組中的每個(gè)元素進(jìn)行累積操作。

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

  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]

五、對(duì)象屬性法

  1. 基本原理:

    • 創(chuàng)建一個(gè)空對(duì)象,將數(shù)組元素作為對(duì)象的屬性名,如果屬性不存在,則將元素添加到新數(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)缺點(diǎn),可以根據(jù)具體情況選擇合適的方法。例如,使用 Set 和擴(kuò)展運(yùn)算符的方法簡(jiǎn)潔高效,但不支持在低版本的瀏覽器中使用;使用 for 循環(huán)和 indexOf 的方法兼容性好,但代碼相對(duì)較長(zhǎng)。

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

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

一、使用正則表達(dá)式

  1. 基本原理:

    • 通過正則表達(dá)式匹配 URL 中的參數(shù)部分,然后解析出各個(gè)參數(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是一個(gè)內(nèi)置的 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"}

三、手動(dòng)解析 URL

  1. 基本原理:

    • 首先獲取 URL 的查詢部分,然后通過分割字符串的方式解析出各個(gè)參數(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,那么使用它是一種比較簡(jiǎn)潔和現(xiàn)代的方式。如果需要兼容舊版本的瀏覽器,可以使用正則表達(dá)式或手動(dòng)解析 URL 的方法。

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

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

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

  1. 發(fā)布者(Publisher):發(fā)布者是產(chǎn)生事件的對(duì)象。當(dāng)發(fā)布者發(fā)生某些事件時(shí),它會(huì)通知事件中心。

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

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

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

  1. 使用對(duì)象實(shí)現(xiàn):

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

    • 以下是一個(gè)使用對(duì)象實(shí)現(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. 使用類實(shí)現(xiàn):

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

    • 以下是一個(gè)使用類實(shí)現(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?方法來訂閱特定的事件。當(dāng)事件發(fā)生時(shí),事件中心會(huì)調(diào)用訂閱者提供的回調(diào)函數(shù)。

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

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

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

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

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

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

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

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

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

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

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

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

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

  1. 內(nèi)存管理:如果訂閱者沒有正確地取消訂閱事件,可能會(huì)導(dǎo)致內(nèi)存泄漏。

  2. 調(diào)試?yán)щy:由于發(fā)布者和訂閱者之間沒有直接的調(diào)用關(guān)系,調(diào)試起來可能會(huì)比較困難。


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


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