1、防抖
防抖限制多长时间执行一次,节流限制多长时间必须执行依次
适用范围 input框实时搜索 防抖
debounce限制多长时间才能执行一次,throttle限制多长时间必须执行一次,一个限制上限、一个限制下限
function debounce(func, delay) {
let timeout = null;.//闭包
return function(e) {
if(timeout){
clearTimeout(timeout)
}
var context = this, args = arguments
timeout = setTimeout(function(){
func.apply(context, args);
},delay)
};
};
// 测试
function task() {
console.log('run task')
}
const debounceTask = debounce(task, 1000)
window.addEventListener('scroll', debounceTask)
2、节流
适用范围在 比input, keyup更频繁触发的事件中,如resize, touchmove, mousemove, scroll。throttle 会强制函数以固定的速率执行。因此这个方法比较适合应用于动画相关的场景。
throttle(fn,delay){
let valid = true
return function() {
if(!valid){
return false
}
var context = this, args = arguments
valid = false
setTimeout(() => {
fn.apply(context, args)
valid = true;
}, delay)
}
}
/////
function throttle(fn, delay) {
let last = 0 // 上次触发时间
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 deeepClone(obj, cache = new WeakMap()) {
if (typeof obj !== 'object') return obj
if (obj === null) return obj
if (cache.get(obj)) return cache.get(obj) // 防止循环引用,程序进入死循环
if (obj instanceof Date) return new Date(obj)
if (obj instanceof RegExp) return new RegExp(obj)
// 找到所属原型上的constructor,所属原型上的constructor指向当前对象的构造函数
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)
4、Promise
class MyPromise {
constructor(executor) { // executor执行器
this.status = 'pending' // 等待状态
this.value = null // 成功或失败的参数
this.fulfilledCallbacks = [] // 成功的函数队列
this.rejectedCallbacks = [] // 失败的函数队列
const that = this
function resolve(value) { // 成功的方法
if (that.status === 'pending') {
that.status = 'resolved'
that.value = value
that.fulfilledCallbacks.forEach(myFn => myFn(that.value)) //执行回调方法
}
}
function reject(value) { //失败的方法
if (that.status === 'pending') {
that.status = 'rejected'
that.value = value
that.rejectedCallbacks.forEach(myFn => myFn(that.value)) //执行回调方法
}
}
try {
executor(resolve, reject)
} catch (err) {
reject(err)
}
}
then(onFulfilled, onRejected) {
if (this.status === 'pending') {
// 等待状态,添加回调函数到成功的函数队列
this.fulfilledCallbacks.push(() => {
onFulfilled(this.value)
})
// 等待状态,添加回调函数到失败的函数队列
this.rejectedCallbacks.push(() => {
onRejected(this.value)
})
}
if (this.status === 'resolved') { // 支持同步调用
console.log('this', this)
onFulfilled(this.value)
}
if (this.status === 'rejected') { // 支持同步调用
onRejected(this.value)
}
}
}
// 测试
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
})
5、异步控制并发数
function limitRequest(urls, limit){
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()
if(url) {
axios.post(url).finally(()=>{
if(count == len - 1){
//完成最后一个任务
resolve()
}else {
// 完成本任务 执行下一个任务
count++
start()
}
})
}
}
})
}
limitRequest(urls, limit)
// 可以批量请求数据,所有的URL地址在urls参数中
// 同时可以通过max参数 控制请求的并发度
// 当所有的请求结束后,需要执行callback回调
function sendRequest(urls, max ,callback){
if(!urls ||!max) return
if(urls.length === 0 ){
if(callback) callback()
return
}
let fetchArr = [],
i =0;
function toFetch(){
if(i === urls.length ) return Promise.resolve()
// 取出第i个url 放进fetch里面
let one = fetch(urls[i++])
// 存入并发数组
fetchArr.push(one)
// 执行完从并发数组删除
one.then(res => {
console.log(res)
fetchArr.splice(fetchArr.indexOf(one), 1)
})
let p = Promise.resolve()
// 当并行数量到达限制后 使用race 比较 第一个完成。然后在调用函数本身
if(fetchArr.length >= max) p = Promise.race(fetchArr)
return p.then(() => toFetch())
}
// 循环完数组,使用all 等待全部执行完后调用回调函数
toFetch()
.then(()=> Promise.all(fetchArr))
.then(()=> callback())
}
sendRequest(urls, max, callback)
6、寄生组合继承
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
Child.prototype.study = function() {
console.log(this.name + "is studying");
}
let child = new Child('xiaoxiao', 16)
console.log(child.name)
child.eat()
child.study()
7、排序
sort 排序
// 对数字排序
const arr =[2,1]
arr.sort((a,b) => a-b)
// 对字母排序
const arr = ['b', 'c', 'a', 'e', 'd']
arr.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、去重
//set去重
cosnt newArr = [...new Set(arr)]
//Array.from 去重
const newArr = Array.from(new Set(arr))
//indexOf 去重
function re(arr) {
let num = []
arr.forEach((item)=>{
if(res.indexOf(item) === -1){
res.push(item)
}
})
return num
}
9、url参数
URLSearchParams
// 创建一个URLSearchParams实例
const urlSearchParams = new URLSearchParams(window.location.search);
// 把键值对列表转换为一个对象
const params = Object.fromEntries(urlSearchParams.entries());
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、发布者/订阅者
// 发布者订阅者模式
class EventEmitter {
constructor() {
this.subs = Object.create(null)
}
// 订阅
$on(eventType,handler) {
this.subs[eventType] = this.subs[eventType] || []
this.subs[eventType].push(handler)
}
// 发布
$emit(eventType) {
console.log(this.subs, 'subs')
console.log(this.subs[eventType], 'event')
if(this.subs[eventType]){
this.subs[eventType].forEach(func => {
func()
});
}
}
}
let em =new EventEmitter();
em.$on('event', () => {
console.log('1号订阅')
})
em.$on('event', () => {
console.log('2号也订阅')
})
setTimeout(()=>{
em.$emit('event')
},3000)