SOURCE

// 防抖

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

// 节流
function throttle(fn, delay) {
    let last = 0
    return function(...args) {
        let now = Date.now()
        if (now - last >= delay) {
            fn.apply(this, args)
            last = now
        }
    }
}

// 深拷贝
function deepClone(obj, cache = new WeakMap()) {
    if (!obj || typeof obj !== 'object') return obj
    if (cache.get(obj)) return cache.get(obj)

    let cloneObj = Array.isArray(obj) ? [] : {}
    cache.set(obj, cloneObj)
    for(let key in obj) {
        if (obj.hasOwnProperty(key)) {
            const temp = obj[key]
            cloneObj[key] = typeof temp === 'object' ? deepClone(temp, cache) : temp
        }
    }
    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

class MyPromise {
    constructor(executor) {
        this.status = 'pending'
        this.value = null
        this.errValue = null
        this.fulfilledCallbacks = []
        this.rejectedCallbacks = []

        const that = this

        function resolve(value) {
            if (that.status === 'pending') {
                that.status = 'resolved'
                that.value = value
                that.fulfilledCallbacks.forEach(fn => fn(that.value))
            }
        }

        function reject(value) {
            if (that.status === 'pending') {
                that.status = 'rejected'
                that.errValue = value
                that.rejectedCallbacks.forEach(fn => fn(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.errValue)
            })
        }

        if (this.status === 'resolved') {
            onFulfilled(this.value)
        }

        if (this.status === 'rejected') {
            onRejected(this.errValue)
        }
    }

    // then实现链式调用
    then1(onFulfilled, onRejected) {
        onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value
        onRejected = typeof onRejected === 'function' ? onRejected : err => { throw err }

        let promise2 = new MyPromise((resolve, reject) => {
            if (this.status === 'pending') {
                this.fulfilledCallbacks.push(() => {
                    setTimeout(() => {
                        try{
                            const x = onFulfilled(this.value)
                            resolvePromise(promise2, x, resolve, reject)
                        } catch(err) {
                            reject(err)
                        }
                    }, 0)
                })
                
                this.rejectedCallbacks.push(() => {
                    setTimeout(() => {
                        try {
                            let x = onRejected(this.errValue)
                            resolvePromise(promise2, x, resolve, reject)
                        } catch (e) {
                            reject(e)
                        }
                    }, 0)
                })
                
            }

            if (this.status === 'resolved') {
                setTimeout(() => {
                    try {
                        const x = onFulfilled(this.value)
                        resolvePromise(promise2, x, resolve, reject) 
                    }catch(e) {
                        reject(e)
                    }
                },0 )
            }

            if (this.status === 'rejected') {
                setTimeout(() => {
                    try {
                        let x = onRejected(this.errValue)
                        resolvePromise(promise2, x, resolve, reject)
                    } catch(e) {
                        reject(e)
                    }
                }, 0)
                
            }
        })

        return promise2
    }

    catch(fn) {
        return this.then1(null, fn)
    }

    // finally(fn) {
    //     return this.then1(fn, fn)
    // }
}

function resolvePromise(promise2, x, resolve, reject) {
    if (x === promise2) {
        return reject(new Error('循环引用'))
    }

    let flag = false
    if(x && (typeof x === 'object' || typeof x === 'function')) {
        try {
            let then = x.then
            if (typeof then === 'function') {
                then.call(x, y=> {
                    if (flag) return
                    flag = true
                    resolvePromise(promise2, y, resolve, reject)
                }, err => {
                    if (flag) return
                    flag = true
                    reject(err)

                })
            } else {
                resolve(x)
            }
        } catch(err) {
            if (flag) return
            flag = true
            reject(err)
        }
    } else {
        resolve(x)
    }
}

MyPromise.resolve = function(value) {
    return new MyPromise((resolve, reject) => {
        resolve(value)
    })
}

MyPromise.reject = function(value) {
    return new MyPromise((resolve, reject) => {
        reject(value)
    })
}


MyPromise.all = function(promises) {
    return new MyPromise((resolve, reject) => {
        let res = [], count = 0, len = promises.length
        for (let i = 0; i < len; i++) {
            promises[i].then(data => {
                res[i] = data
                count++
                if (count === len) {
                    resolve(res)
                }
            }, (err) => {
                reject(err)
            }) 
        }
    })
}

MyPromise.race = function(promises) {
    let len = promises.length
    return new MyPromise((resolve, reject) => {
        for (let i = 0; i < len; i++) {
            promises[i].then(data => {
                 resolve(data)
            }, (err) => {
                reject(err)
            }) 
        }
    })
}

MyPromise.any = function(promises) {
    return new MyPromise((resolve, reject) => {
        let index = 0, len = promises.length
        for (let i = 0; i < len; i++) {
            promises[i].then(data => {
                 resolve(data)
            }, (err) => {
                index++ 
                if (index === len) {
                    reject(new Error('All promises rejected'))
                }
            }) 
        }
    })
}

MyPromise.allSettled = function(promises) {
    if (promises.length === 0) return MyPromise.resolve([])
    return new MyPromise((resolve, reject) => {
        let res = [], count = 0, len = promises.length
        for (let i = 0; i < len; i++) {
            promises[i].then(value => {
                res[i] = {
                    status: 'fulfilled',
                    value
                }
                count++
                if (count === len) {
                    resolve(res)
                }
            }, reason => {
                res[i] = {
                    status: 'rejected',
                    reason
                }
                count++
                if (count === len) {
                    reject(res)
                }
            }) 
        }
    })
}


MyPromise.prototype.finally = function(fn) {
    return this.then1((data) => {
        return  MyPromise.resolve(fn()).then(() => data)
    }, err => {
        return  MyPromise.resolve(fn()).then(() => { throw err })
    })
}


// 测试
const fn = 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
//     }
// )

// fn.then1(res => {
//     console.log('res1111', res) // res 1
// }).then1(() => {
//     console.log('aaa')
// })

// fn.then1(res => {
//     console.log('res1111', res) // res 1
// }).catch((err) => {
//     console.log(err)
// }).finally(() => {
//     console.log('finally')
// })

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

        const start = async () => {
            const url = urls.shift()
            if (url) {
                try{
                    await axios.post(url)
                    if (count === len - 1) {
                        resolve()
                    } else {
                        count++
                        start()
                    }
                } catch(err) {
                    count++
                    start()
                }
            }
        }

        while(limit > 0) {
            start()
            limit--
        }
    })
}

// ES5 寄生组合式继承

function Parent(name) {
    this.name = name
}

Parent.prototype.sayName = function() {
    console.log('My name is ' + this.name)
}

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

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

// sort排序
var arr= [2, 3, 6, 8, 1, 5, 4, 9]
arr.sort((a, b) => a-b) // 升序
// console.log(arr)

arr.sort((a, b) => b-a) // 降序
// console.log(arr)

// 冒泡排序
function bubbleSort(arr) {
    let len = arr.length
    for (let i = 0; i < len; i++) {
        for(let j = 0; j < len - i; j++) {
            if (arr[j] > arr[j + 1]) {
                let temp = arr[j]
                arr[j] = arr[j + 1]
                arr[j + 1] = temp
            }
        }
    }
    return arr 
}

// console.log(bubbleSort([2, 3, 6, 8, 1, 5, 4, 9])) // [1, 2, 3, 4, 5]


// 数组去重
var arr = [1, 1, 2, 3, 3]

var newArr = [...new Set(arr)]
// console.log(newArr) // [1, 2, 3]

var newArr = Array.from(new Set(arr))
// console.log(newArr) // [1, 2, 3]

function unique(arr) {
    let res = []
    arr.forEach(item => {
        if (res.indexOf(item) === -1) {
            res.push(item)
        }
    })
    return res
}
// console.log(unique(arr)) // [1, 2, 3]


function unique(arr) {
    return arr.filter((item, index, arr) => {
        return arr.indexOf(item) === index
    })
}
// console.log(unique(arr)) // [1, 2, 3]

function unique(arr) {
    return arr.reduce((acc, cur) => {
        if (!acc.includes(cur)) {
            acc.push(cur)
        }
        return acc
    }, [])
}
// console.log(unique(arr)) // [1, 2, 3]



// 获取url上的参数
function getParams(url) {
    const res = {}
    let str = ''
    if (url.includes('?')) {
        str = url.split('?')[1]
    }
    if (url.includes('#')) {
        str = str.split('#')[0]
    }

    const arr = str.split('&')
    arr.forEach(item => {
        const [key, val] = item.split('=')
        // res[key] = val
        res[key] = decodeURIComponent(val)
    })

    return res
}

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

var user = getParams('http://www.baidu.com?user=%E9%98%BF%E9%A3%9E&age=16#hasKey')
// console.log(user) // { user: '阿飞', age: '16' }


// 事件总线|发布订阅模式
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 > -1) {
                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)


// 数组扁平化
function flatArr(arr, depth = 1) {
    if (!Array.isArray(arr) || depth <= 0) return arr

    let res = arr.reduce((prev, cur) => {
        if (Array.isArray(cur)) {
            return prev.concat(flatArr(cur, depth - 1))
        } else {
            return prev.concat(cur)
        }
    }, [])
    return res
}

var arr = [1, 2, [3, 4], [5, [6, 7]]]
// console.log(flatArr(arr, 3))


Array.prototype.myForEach = function(fn) {
    if (!this || !Array.isArray(this)) {
        throw new Error('this must be an Array')
    }

    if (typeof fn !== 'function') {
        throw new Error('fn must be a function')
    }

    const arr = this, thisArg = arguments[1] || window, len = this.length
    for (let i = 0; i < len; i++) {
        fn.call(thisArg, arr[i], i, arr)
    }
}


Array.prototype.myReduce = function(fn) {
    if (!this || !Array.isArray(this)) {
        throw new Error('this must be an Array')
    }

    if (typeof fn !== 'function') {
        throw new Error('fn must be a function')
    }

    const arr = this,  len = this.length
    let res = arguments[1], i = 0
    if (res === undefined) {
        if (len === 0) {
            throw new Error('initVal and array.length need one')
        }
        res = arr[i]
        i++;
    }

    for (;i < len; i++) {
        res = fn(res, arr[i], i, arr)
    }
    return res
}

var arr = [1, 2, 3, 4]
var sum = arr.myReduce((prev, next) => {
    return prev + next
}, 0)

// console.log(sum) // -> 10


function createObj(fn) {
    const obj = Object.create(null)
    // obj.__proto__ = fn.prototype
    Object.setPrototypeOf(obj, fn.prototype)

    let res = fn.apply(obj, [].slice.call(arguments, 1))
    return res && (typeof res === 'object' || typeof res === 'function') ? res : obj
}

var arr = [1, 1, 2, 3, 3, 4, 4, 3, 5]
function dd(arr) {
    let res = []
    let temp = []
    arr.forEach((item, index) => {
        if (!temp.includes(item)) {
           temp[index] = item
        }
        if (!temp[index] && !res.includes(item)) {
            res.push(item)
        }
    })
    return res
}

// console.log(dd(arr))

var str = "100000000",
    reg = /(?=(\B\d{3})+$)/g;
str = str.replace(reg, ",")
// console.log(str)


// 将数字每千分位用逗号隔开
function formatNum(num) {
    let numStr= num.toString(),
        intNum = numStr,
        xiaoshu = ''

    if (numStr.indexOf('.') > -1) {
       [intNum, xiaoshu] = numStr.split('.')
    } 

    let res = []
    intNum.split('').reverse().forEach((item, index, arr) => {
        res.push(item)
        if (index > 0 && index % 3 === 2 && index < arr.length - 1) {
            res.push(',')
        }
    })

    intNum = res.reverse().join('')

    return xiaoshu ? intNum + '.' + xiaoshu : intNum
}

// console.log(formatNum(str))
// console.log(formatNum(100343333.55))

function lengthOfLongestSubstring(s) {
    let map = new Map(),
        res = 0,
        i = -1,
        len = s.length
    for(let j = 0; j < len; j++) {
        if (map.has(s[j])) {
            i = Math.max(i, map.get(s[j]))
        }
        res = Math.max(res, j - i)
        map.set(s[j], j)
    }
    return res
}

console.log(lengthOfLongestSubstring('adrrefsfds'))
console 命令行工具 X clear

                    
>
console