10个常见的JavaScript函数的前端手写功能,你都知道吗?
英文 | https://medium.com/@cookbug/10-common-front-end-handwriting-functions-do-you-know-all-of-them-9deb1ffb922d
翻译 | 杨小爱
function debounce(fn, delay) {
let timer
return function (…args) {
if (timer) {
clearTimeout(timer)
}
timer = setTimeout(() => {
fn.apply(this, args)
}, delay)
}
}
// test
function task() {
console.log(‘run task’)
}
const debounceTask = debounce(task, 1000)
window.addEventListener(‘scroll’, debounceTask)
2、节流
function throttle(fn, delay) {
let last = 0 // Last trigger time
return (…args) => {
const now = Date.now()
if (now-last> delay) {
last = now
fn.apply(this, args)
}
}
}
// test
function task() {
console.log(‘run task’)
}
const throttleTask = throttle(task, 1000)
window.addEventListener(‘scroll’, throttleTask)
3、深拷贝
function deepClone(obj, cache = new WeakMap()) {
if (typeof obj !==’object’) return obj
if (obj === null) return obj
if (cache.get(obj)) return cache.get(obj) // Prevent circular references, the program enters an infinite loop
if (obj instanceof Date) return new Date(obj)
if (obj instanceof RegExp) return new RegExp(obj)
// Find the constructor on the owning prototype, and the constructor on the owning prototype points to the constructor of the current object
let cloneObj = new obj.constructor()
cache.set(obj, cloneObj) // Cache copied objects, used to handle circular references
for (let key in obj) {
if (obj.hasOwnProperty(key)) {
cloneObj[key] = deepClone(obj[key], cache) // recursive copy
}
}
return cloneObj
}
// test
const obj = {name:’Jack’, address: {x: 100, y: 200}}
obj.a = obj // circular reference
const newObj = deepClone(obj)
console.log(newObj.address === obj.address) // false
4、Promise 的实现
class MyPromise {
constructor(executor) {// executor executor
this.status =’pending’ // waiting status
this.value = null // parameter of success or failure
this.fulfilledCallbacks = [] // Successful function queue
this.rejectedCallbacks = [] // Failed function queue
const that = this
function resolve(value) {// successful method
if (that.status ===’pending’) {
that.status =’resolved’
that.value = value
that.fulfilledCallbacks.forEach(myFn => myFn(that.value)) //Execute callback method
}
}
function reject(value) {//Failed method
if (that.status ===’pending’) {
that.status =’rejected’
that.value = value
that.rejectedCallbacks.forEach(myFn => myFn(that.value)) //Execute callback method
}
}
try {
executor(resolve, reject)
} catch (err) {
reject(err)
}
}
then(onFulfilled, onRejected) {
if (this.status ===’pending’) {
// Waiting state, add the callback function to the successful function queue
this.fulfilledCallbacks.push(() => {
onFulfilled(this.value)
})
// Waiting state, add the callback function to the failed function queue
this.rejectedCallbacks.push(() => {
onRejected(this.value)
})
}
if (this.status ===’resolved’) {// support synchronous call
console.log(‘this’, this)
onFulfilled(this.value)
}
if (this.status ===’rejected’) {// Support synchronous call
onRejected(this.value)
}
}
}
// test
function fn() {
return new MyPromise((resolve, reject) => {
setTimeout(() => {
if(Math.random()> 0.6) {
resolve(1)
} else {
reject(2)
}
}, 1000)
})
}
fn().then(
res => {
console.log(‘res’, res) // res 1
},
err => {
console.log(‘err’, err) // err 2
})
function limitRequest(urls = [], limit = 3) {
return new Promise((resolve, reject) => {
const len = urls.length
let count = 0
// Start limit tasks simultaneously
while (limit> 0) {
start()
limit -= 1
}
function start() {
const url = urls.shift() // Take the first task from the array
if (url) {
axios.post(url).finally(() => {
if (count == len-1) {
// The last task is completed
resolve()
} else {
// After completion, start the next task
count++
start()
}
})
}
}
})
}
// test
limitRequest([‘http://xxa','http://xxb','http://xxc','http://xxd','http://xxe'])
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
Child.prototype.study = function () {
console.log(this.name + ‘is studying’)
}
// test
let child = new Child(‘xiaoming’, 16)
console.log(child.name) // xiaoming
child.eat() // xiaoming is eating
child.study() // xiaoming is studying
7、数组排序
//sort
// Sort the numbers, abbreviated
const arr = [3, 2, 4, 1, 5]
arr.sort((a, b) => a-b)
console.log(arr) // [1, 2, 3, 4, 5]
// Sort the letters, abbreviated
const arr = [‘b’,’c’,’a’,’e’,’d’]
arr.sort()
console.log(arr) // [‘a’,’b’,’c’,’d’,’e’]
//Bubble Sort
function bubbleSort(arr) {
let len = arr.length
for (let i = 0; i <len-1; i++) {
// Starting from the first element, compare two adjacent elements, exchange positions if the former is bigger
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
}
}
// At the end of each traversal, a maximum value can be found and placed at the end of the array
}
return arr
}
//test
console.log(bubbleSort([2, 3, 1, 5, 4])) // [1, 2, 3, 4, 5]
8、阵列去重
cosnt newArr = […new Set(arr)]
Array.from 去重
const newArr = Array.from(new Set(arr))
重复数据删除索引
function resetArr(arr) {
let res = []
arr.forEach(item => {
if (res.indexOf(item) === -1) {
res.push(item)
}
})
return res
}
// test
const arr = [1, 1, 2, 3, 3]
console.log(resetArr(arr)) // [1, 2, 3]
9、获取url参数
URLSearchParams 方法
// Create an instance of URLSearchParams
const urlSearchParams = new URLSearchParams(window.location.search);
// Convert the list of key-value pairs into an object
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) // decode
})
}
return res
}
// test
const user = getParams(‘http://www.baidu.com?user=%E9%98%BF%E9%A3%9E&age=16')
console.log(user) // {user:’abor’, age: ‘16’}
10、 事件总线 | 发布和订阅模式
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]) {
// Create a copy, if you continue to register the same event in the callback function, it will cause an endless loop
const tasks = this.cache[name].slice()
for (let fn of tasks) {
fn();
}
if (once) {
delete this.cache[name]
}
}
}
}
// test
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)
学习更多技能
请点击下方公众号
评论