SOURCE

/******************* 继承 *************************/ 
// 寄生继承
function Animal(name, age) {
    this.name = name
    this.age = age
}
Animal.prototype.eat = () => {
    console.log('eat')
}

function Dog(name, age, hoppy) {
    Animal.call(this, name, age)
    this.hoppy = hoppy
}
const inhertParent = (child, Parent) => {
    const prototype = Object.create(Parent.prototype)
    child.prototype = prototype
    child.prototype.constructor = Parent
}

inhertParent(Dog, Animal)

/******************* 防抖与节流 *************************/ 
// 防抖
let debounce = (fn, delay) => {
    let timer = null
    return function(...args) {
        const context = this;
        if(timer) {
            clearTimeout(timer)
            timer = null
        }
        setTimeout(()=> {
            fn.apply(context, args)
        }, delay)
    }
}
// 节流
let throttle = (fn, delay) => {
    let currentTime = Date.now()
    return function(...args) {
        const context = this
        const nowTime = Date.now()
        if(currentTime - nowTime >= delay) {
            return fn.apply(context, args)
            currentTime = Date.now()
        }
    }
}

/******************* 函数借用三剑客 *************************/ 
// call
// fn.call(this, arg1, arg2)
function myCall(context=window, ...args) {
    if(!this) {
        throw new Error('error')
    }
    let result = null
    context.fn = this
    result = context.fn(...args)
    delete context.fn
    return result 
}

// apply
// fn.apply(this, ...args)
function myCall(context=window, ...args) {
    if(!this) {
        throw new Error('error')
    }
    let result = null
    context.fn = this
    if(args && args.length > 0) {
        result = context.fn(...args)
    } else {
        result = context.fn()
    }
    
    delete context.fn
    return result 
}

// bind
// fn.bind(this, arg1, arg2...)
function myCall(context=window, ...args) {
    if(!this) {
        throw new Error('error')
    }
    const self = this
    return function() {
        return self.apply(context, args)
    }
}


/******************* 去重三版 *************************/ 
// map版本
function removeDuplicate(arr) {
    let map = new Map()
    let result = []
    for(let i=0; i<arr.length; i++) {
        if(!map.has(arr[i])) {
            map.set(arr[i], arr[i])
            result.push(arr[i])
        }
    }
    return result
}

// indexof版本
function removeDuplicateIndexOf(arr) {
    let result = []
    for(let i=0; i<arr.length; i++) {
        if(result.indexOf(arr[i]) === -1) {
           result.push(arr[i])
        }
    }
    return result
}

// includes版本
function removeDuplicateIncludes(arr) {
    let result = []
    for(let i=0; i<arr.length; i++) {
        if(!result.includes(arr[i])) {
           result.push(arr[i])
        }
    }
    return result
}


/******************* 扁平化数组 *************************/ 
// ES6 
let arr = [1,2,3,[4,5,[6,[7,8,[9,10]]]]];
// console.log(arr.flat(Infinity))

// 递归
function flat(arr) {
    let result = []
    for(let i=0;i<arr.length;i++) {
        const current = arr[i]
        if(Array.isArray(current)) {
            result = [...result, ...flat(current)]
        } else {
            result = [...result, current]
        }
    }
    return result
}
// console.log(flat(arr))


/******************* 数组转换成树 *************************/ 
// 转换前:
let source = [{
            id: 1,
            pid: 0,
            name: 'body'
          }, {
            id: 2,
            pid: 1,
            name: 'title'
          }, {
            id: 3,
            pid: 2,
            name: 'div'
          }]
// 转换为: 
let tree = [{
          id: 1,
          pid: 0,
          name: 'body',
          children: [{
            id: 2,
            pid: 1,
            name: 'title',
            children: [{
              id: 3,
              pid: 1,
              name: 'div'
            }]
          }]
        }]


 [{
            id: 1,
            pid: 0,
            name: 'body'
          }, {
            id: 2,
            pid: 1,
            name: 'title'
          }, {
            id: 3,
            pid: 2,
            name: 'div'
          }]


function convertTree(arr) {
    if(!Array.isArray(arr)) return arr
    let map = {}
    let result = []
    arr.forEach(item => {
        map[item.id] = item
    })
    arr.forEach(item => {
        let parent = map[item.pid]
        if(parent) {
            ((parent.children) || (parent.children = [])).push(item)
        } else {
            result.push(item)
        }
    })
    return result
}

// console.log(convertTree(source))


/******************* Url对象解析 *************************/ 

let url = 'http://www.domain.com/?user=anonymous&id=123&id=456&id=456&city=%E5%8C%97%E4%BA%AC&enabled';
// console.log(parseParam(url))
/* 结果
{ user: 'anonymous',
  id: [ 123, 456 ], // 重复出现的 key 要组装成数组,能被转成数字的就转成数字类型
  city: '北京', // 中文需解码
  enabled: true, // 未指定值得 key 约定为 true
}
*/

function parseParam(url) {
    let param = url.split('?')[1]
    let paramArr = param.split('&')
    let result = {}
    paramArr.forEach(item => {
        if(item.indexOf('=')!==-1) {
            const [key, value] = item.split('=')
            if(result[key]) {
                const lastValue = result[key]
                result[key] = Array.isArray(lastValue) ? [...lastValue, value] : [lastValue, value]
            } else {
                result[key] = decodeURIComponent(value)
            }
        } else {
            result[item] = true
        }
    })
    return result
}

/******************* 千分位分割 *************************/ 

const cash = 1234567
function getReverse(str) {
    return str.split('').reverse().join('')
}
function formatCash(number) {
    number = number + ''
    let cash = number
    let last = ''
    if(cash.indexOf('.') > -1) {
        cash = number.split('.')[0]
        last = number.split('.')[1]
    }
    cash = getReverse(cash)
    const count = Math.ceil(cash.length / 3)
    let i = 0
    let result = []
    while(i !== count) {
        let sliceStr = cash.slice(i*3 , ++i * 3)
        sliceStr = getReverse(sliceStr)
        result = [sliceStr, ...result]
    }
    return `${result.join(',')}.${last}`
}
// console.log(formatCash(cash))

// 根据string可以直接通过索引的方式取值
function format(number, thousandsSeperator) {
    const s = String(number)
    let r = ''
    for (let i = s.length - 1; i >= 0; i--) {
        const seperator = (s.length - i - 1) % 3 ? '' : thousandsSeperator
        r = `${s[i]}${seperator}${r}`
    }
    return r.slice(0, -1)
}

format(cash, ',')

/******************* 洗牌算法(打乱数组) *************************/ 

// 思路就是每次从数组的第n个取值(n从数组尾部开始),
// 在随机生成0 ~ n-1的索引然后互相交换他们的值即可;

function shuffle(arr) {
    let currentIndex = arr.length;
    while(currentIndex) {
        const randomIndex = Math.floor(Math.random() * currentIndex--)
        const currentValue = arr[currentIndex]
        arr[currentIndex] = arr[randomIndex]
        arr[randomIndex] = currentValue
    } 
    return arr
}
// console.log(shuffle([1,2,3]))


/*
  请实现一个 sum 函数,接收一个数组 arr 进行累加,并且只能使用add异步方法
  
  add 函数已实现,模拟异步请求后端返回一个相加后的值
*/
function add(a, b) {
  return Promise.resolve(a + b);
}

// async 
async function asyncSum(arr) {
    let result = 0
    for(let i = 0; i < arr.length ; i++) {
        result = await add(result, arr[i])
    }
    console.log(result)
    return result
}
promiseSum([1,2,3])

// 斐波那契数列
// 本质就是 0 1,从2开始等于前面两个数的和
function fn(n) {
    let n1 = 1, n2 = 1
    for(let i = 2;i<n;i++) {
        [n1, n2] = [n2, n1 + n2]
    }
    return n2
}

function fn1(n) {
    let n1 = 1, n2 = 1, sum;
    for(let i=2; i<n;i++) {
        sum = n1 + n2
        n1 = n2
        n2 = sum
    }
    return sum
}

// interval
function mySetInterval(fn, timeout) {
  var timer = {
    flag: true
  };
  function interval() {
    if (timer.flag) {
      fn();
      setTimeout(interval, timeout);
    }
  }
  setTimeout(interval, timeout);
  return timer;
}
console 命令行工具 X clear

                    
>
console