When a building is built from the ground up, it is only when the foundation is firmly laid that it will always be invincible. Today we bring you 10 common JavaScript handwriting functions, important places have been added comments. Some of them are borrowed from others, some are written by myself, if there is something incorrect, welcome to correct it.
1. Anti-shake
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. Throttling
function throttle(fn, delay) {
let last = 0
return function (...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、Deep Copy
JSON method
const cloneObj = JSON.parse(JSON.stringify(obj))
recursive copy
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.has(obj)) return cache.get(obj)
let cloneObj = new obj.constructor()
cache.set(obj, cloneObj)
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
const newObj = deepClone(obj)
console.log(newObj.address === obj.address) // false
4、Handwriting Promise
class MyPromise {
constructor(executor) {
this.status = 'pending'
this.value = null
this.reason = null
this.onFulfilledCallbacks = []
this.onRejectedCallbacks = []
let resolve = value => {
if (this.status === 'pending') {
this.status = 'fulfilled'
this.value = value;
this.onFulfilledCallbacks.forEach(fn => fn())
}
}
let reject = reason => {
if (this.status === 'pending') {
this.status = 'rejected'
this.reason = reason
this.onRejectedCallbacks.forEach(fn => fn())
}
};
try {
executor(resolve, reject)
} catch (err) {
reject(err)
}
}
then(onFulfilled, onRejected) {
return new MyPromise((resolve, reject) => {
if (this.status === 'fulfilled') {
setTimeout(() => {
const x = onFulfilled(this.value);
x instanceof MyPromise ? x.then(resolve, reject) : resolve(x)
})
}
if (this.status === 'rejected') {
setTimeout(() => {
const x = onRejected(this.reason)
x instanceof MyPromise ? x.then(resolve, reject) : resolve(x)
})
}
if (this.status === 'pending') {
this.onFulfilledCallbacks.push(() => {
setTimeout(() => {
const x = onFulfilled(this.value)
x instanceof MyPromise ? x.then(resolve, reject) : resolve(x)
})
})
this.onRejectedCallbacks.push(() => {
setTimeout(() => {
const 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. Asynchronous control of the number of concurrency
function limitRequest(urls = [], limit = 3) {
return new Promise((resolve, reject) => {
const len = urls.length
let count = 0
while (limit > 0) {
start()
limit -= 1
}
function start() {
const url = urls.shift()
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. Succession
ES5 Inheritance (Parasitic Combinatorial Inheritance)
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.constructor = Child
let xm = new Child('xiaoming', 12)
console.log(xm.name) // xiaoming
console.log(xm.age) // 12
xm.eat() // xiaoming is eating
ES6 Inheritance
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. Array sorting
sort Sort
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']
bubbling sort
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
}
}
}
return arr
}
console.log(bubbleSort([2, 3, 1, 5, 4])) // [1, 2, 3, 4, 5]
8, array de-emphasis
Set de-duplication
const newArr = [...new Set(arr)]
const newArr = Array.from(new Set(arr))
indexOf De-weighting
const newArr = arr.filter((item, index) => arr.indexOf(item) === index)
9、Get url parameter
URLSearchParams 方法
const urlSearchParams = new URLSearchParams(window.location.search);
const params = Object.fromEntries(urlSearchParams.entries());
split method
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('https://www.discountstaken.com?user=%E9%98%BF%E9%A3%9E&age=16')
console.log(user) // { user: 'af', age: '16' }
10. Publishing the subscription model
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]) {
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)