亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

分享10個常見的JavaScript前端手寫功能

 更新時間:2022年02月14日 10:50:23   作者:前端阿飛  
這篇文章主要分享10個常見的前端手寫功能,防抖、節(jié)流、深拷貝、異步控制并發(fā)數(shù)、繼承等功能技巧,具有一定的參考價值,需要的小伙伴可以參考一下

1、防抖

function debounce(fn, delay) {
? let timer
? return function (...args) {
? ? if (timer) {
? ? ? clearTimeout(timer)
? ? }
? ? timer = setTimeout(() => {
? ? ? fn.apply(this, args)
? ? }, delay)
? }
}

// 測試
function task() {
? console.log('run task')
}
const debounceTask = debounce(task, 1000)
window.addEventListener('scroll', debounceTask)

2、節(jié)流

function throttle(fn, delay) {
? let last = 0 // 上次觸發(fā)時間
? return (...args) => {
? ? const now = Date.now()
? ? if (now - last > delay) {
? ? ? last = now
? ? ? fn.apply(this, args)
? ? }
? }
}

// 測試
function task() {
? console.log('run task')
}
const throttleTask = throttle(task, 1000)
window.addEventListener('scroll', throttleTask)

3、深拷貝

function deepClone(obj, cache = new WeakMap()) {
? if (obj === null || typeof obj !== 'object') return obj
? if (obj instanceof Date) return new Date(obj)
? if (obj instanceof RegExp) return new RegExp(obj)
??
? if (cache.get(obj)) return cache.get(obj) // 如果出現(xiàn)循環(huán)引用,則返回緩存的對象,防止遞歸進入死循環(huán)
? let cloneObj = new obj.constructor() // 使用對象所屬的構造函數(shù)創(chuàng)建一個新對象
? cache.set(obj, cloneObj) // 緩存對象,用于循環(huán)引用的情況

? for (let key in obj) {
? ? if (obj.hasOwnProperty(key)) {
? ? ? cloneObj[key] = deepClone(obj[key], cache) // 遞歸拷貝
? ? }
? }
? return cloneObj
}

// 測試
const obj = { name: 'Jack', address: { x: 100, y: 200 } }
obj.a = obj // 循環(huán)引用
const newObj = deepClone(obj)
console.log(newObj.address === obj.address) // false

4、手寫 Promise

class MyPromise {
? constructor(executor) {
? ? this.status = 'pending' // 初始狀態(tài)為等待
? ? this.value = null // 成功的值
? ? this.reason = null // 失敗的原因
? ? this.onFulfilledCallbacks = [] // 成功的回調函數(shù)存放的數(shù)組
? ? this.onRejectedCallbacks = [] // 失敗的回調函數(shù)存放的數(shù)組
? ? let resolve = value => {
? ? ? if (this.status === 'pending') {
? ? ? ? this.status = 'fulfilled'
? ? ? ? this.value = value;
? ? ? ? this.onFulfilledCallbacks.forEach(fn => fn()) // 調用成功的回調函數(shù)
? ? ? }
? ? }
? ? let reject = reason => {
? ? ? if (this.status === 'pending') {
? ? ? ? this.status = 'rejected'
? ? ? ? this.reason = reason
? ? ? ? this.onRejectedCallbacks.forEach(fn => fn()) // 調用失敗的回調函數(shù)
? ? ? }
? ? };
? ? try {
? ? ? executor(resolve, reject)
? ? } catch (err) {
? ? ? reject(err)
? ? }
? }
? then(onFulfilled, onRejected) {
? ? // onFulfilled如果不是函數(shù),則修改為函數(shù),直接返回value
? ? onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value
? ? // onRejected如果不是函數(shù),則修改為函數(shù),直接拋出錯誤
? ? onRejected = typeof onRejected === 'function' ? onRejected : err => { throw err }
? ? return new MyPromise((resolve, reject) => {
? ? ? if (this.status === 'fulfilled') {
? ? ? ? setTimeout(() => {
? ? ? ? ? try {
? ? ? ? ? ? let x = onFulfilled(this.value);
? ? ? ? ? ? x instanceof MyPromise ? x.then(resolve, reject) : resolve(x)
? ? ? ? ? } catch (err) {
? ? ? ? ? ? reject(err)
? ? ? ? ? }
? ? ? ? })
? ? ? }
? ? ? if (this.status === 'rejected') {
? ? ? ? setTimeout(() => {
? ? ? ? ? try {
? ? ? ? ? ? let x = onRejected(this.reason)
? ? ? ? ? ? x instanceof MyPromise ? x.then(resolve, reject) : resolve(x)
? ? ? ? ? } catch (err) {
? ? ? ? ? ? reject(err)
? ? ? ? ? }
? ? ? ? })
? ? ? }
? ? ? if (this.status === 'pending') {
? ? ? ? this.onFulfilledCallbacks.push(() => { // 將成功的回調函數(shù)放入成功數(shù)組
? ? ? ? ? setTimeout(() => {
? ? ? ? ? ? let x = onFulfilled(this.value)
? ? ? ? ? ? x instanceof MyPromise ? x.then(resolve, reject) : resolve(x)
? ? ? ? ? })
? ? ? ? })
? ? ? ? this.onRejectedCallbacks.push(() => { // 將失敗的回調函數(shù)放入失敗數(shù)組
? ? ? ? ? setTimeout(() => {
? ? ? ? ? ? let x = onRejected(this.reason)
? ? ? ? ? ? x instanceof MyPromise ? x.then(resolve, reject) : resolve(x)
? ? ? ? ? })
? ? ? ? })
? ? ? }
? ? })
? }
}

// 測試
function p1() {
? return new MyPromise((resolve, reject) => {
? ? setTimeout(resolve, 1000, 1)
? })
}
function p2() {
? return new MyPromise((resolve, reject) => {
? ? setTimeout(resolve, 1000, 2)
? })
}
p1().then(res => {
? console.log(res) // 1
? return p2()
}).then(ret => {
? console.log(ret) // 2
})

5、異步控制并發(fā)數(shù)

function limitRequest(urls = [], limit = 3) {
? return new Promise((resolve, reject) => {
? ? const len = urls.length
? ? let count = 0

? ? // 同時啟動limit個任務
? ? while (limit > 0) {
? ? ? start()
? ? ? limit -= 1
? ? }

? ? function start() {
? ? ? const url = urls.shift() // 從數(shù)組中拿取第一個任務
? ? ? if (url) {
? ? ? ? axios.post(url).then(res => {
? ? ? ? ? // todo
? ? ? ? }).catch(err => {
? ? ? ? ? // todo
? ? ? ? }).finally(() => {
? ? ? ? ? if (count == len - 1) {
? ? ? ? ? ? // 最后一個任務完成
? ? ? ? ? ? resolve()
? ? ? ? ? } else {
? ? ? ? ? ? // 完成之后,啟動下一個任務
? ? ? ? ? ? count++
? ? ? ? ? ? start()
? ? ? ? ? }
? ? ? ? })
? ? ? }
? ? }

? })
}

// 測試
limitRequest(['http://xxa', 'http://xxb', 'http://xxc', 'http://xxd', 'http://xxe'])

6、繼承

ES5繼承(寄生組合繼承)

function Parent(name) {
? this.name = name
}
Parent.prototype.eat = function () {
? console.log(this.name + ' is eating')
}

function Child(name, age) {
? Parent.call(this, name)
? this.age = age
}
Child.prototype = Object.create(Parent.prototype)
Child.prototype.contructor = Child

// 測試
let xm = new Child('xiaoming', 12)?
console.log(xm.name) // xiaoming
console.log(xm.age) // 12
xm.eat() // xiaoming is eating

ES6繼承:

class Parent {
? constructor(name) {
? ? this.name = name
? }
? eat() {
? ? console.log(this.name + ' is eating')
? }
}

class Child extends Parent {
? constructor(name, age) {
? ? super(name)
? ? this.age = age
? }
}

// 測試
let xm = new Child('xiaoming', 12)?
console.log(xm.name) // xiaoming
console.log(xm.age) // 12
xm.eat() // xiaoming is eating

7、數(shù)組排序

sort 排序:

// 對數(shù)字進行排序,簡寫
const arr = [3, 2, 4, 1, 5]
arr.sort((a, b) => a - b)
console.log(arr) // [1, 2, 3, 4, 5]

// 對字母進行排序,簡寫
const arr = ['b', 'c', 'a', 'e', 'd']
arr.sort()
console.log(arr) // ['a', 'b', 'c', 'd', 'e']

冒泡排序:

function bubbleSort(arr) {
? let len = arr.length
? for (let i = 0; i < len - 1; i++) {
? ? // 從第一個元素開始,比較相鄰的兩個元素,前者大就交換位置
? ? for (let j = 0; j < len - 1 - i; j++) {
? ? ? if (arr[j] > arr[j + 1]) {
? ? ? ? let num = arr[j]
? ? ? ? arr[j] = arr[j + 1]
? ? ? ? arr[j + 1] = num
? ? ? }
? ? }
? ? // 每次遍歷結束,都能找到一個最大值,放在數(shù)組最后
? }
? return arr
}

//測試
console.log(bubbleSort([2, 3, 1, 5, 4])) // [1, 2, 3, 4, 5]

8、數(shù)組去重

Set 去重:

const newArr = [...new Set(arr)]
// 或
const newArr = Array.from(new Set(arr))

indexOf 去重:

function resetArr(arr) {
? let res = []
? arr.forEach(item => {
? ? if (res.indexOf(item) === -1) {
? ? ? res.push(item)
? ? }
? })
? return res
}

// 測試
const arr = [1, 1, 2, 3, 3]
console.log(resetArr(arr)) // [1, 2, 3]

9、獲取 url 參數(shù)

URLSearchParams 方法:

// 創(chuàng)建一個URLSearchParams實例
const urlSearchParams = new URLSearchParams(window.location.search);
// 把鍵值對列表轉換為一個對象
const params = Object.fromEntries(urlSearchParams.entries());

split 方法:

function getParams(url) {
? const res = {}
? if (url.includes('?')) {
? ? const str = url.split('?')[1]
? ? const arr = str.split('&')
? ? arr.forEach(item => {
? ? ? const key = item.split('=')[0]
? ? ? const val = item.split('=')[1]
? ? ? res[key] = decodeURIComponent(val) // 解碼
? ? })
? }
? return res
}

// 測試
const user = getParams('http://www.baidu.com?user=%E9%98%BF%E9%A3%9E&age=16')
console.log(user) // { user: '阿飛', age: '16' }

10、事件總線 | 發(fā)布訂閱模式

class EventEmitter {
? constructor() {
? ? this.cache = {}
? }

? on(name, fn) {
? ? if (this.cache[name]) {
? ? ? this.cache[name].push(fn)
? ? } else {
? ? ? this.cache[name] = [fn]
? ? }
? }

? off(name, fn) {
? ? const tasks = this.cache[name]
? ? if (tasks) {
? ? ? const index = tasks.findIndex((f) => f === fn || f.callback === fn)
? ? ? if (index >= 0) {
? ? ? ? tasks.splice(index, 1)
? ? ? }
? ? }
? }

? emit(name, once = false) {
? ? if (this.cache[name]) {
? ? ? // 創(chuàng)建副本,如果回調函數(shù)內繼續(xù)注冊相同事件,會造成死循環(huán)
? ? ? const tasks = this.cache[name].slice()
? ? ? for (let fn of tasks) {
? ? ? ? fn();
? ? ? }
? ? ? if (once) {
? ? ? ? delete this.cache[name]
? ? ? }
? ? }
? }
}

// 測試
const eventBus = new EventEmitter()
const task1 = () => { console.log('task1'); }
const task2 = () => { console.log('task2'); }

eventBus.on('task', task1)
eventBus.on('task', task2)
eventBus.off('task', task1)
setTimeout(() => {
? eventBus.emit('task') // task2
}, 1000)

以上就是工作或求職中最常見的手寫功能

到此這篇關于分享10個常見的前端手寫功能的文章就介紹到這了,更多相關端手寫功能內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

最新評論