js手写题

59 阅读3分钟

1、实现compose函数

function fn1(x) {
	return x + 1
}
function fn2(x) {
	return x + 2
}
function fn3(x) {
	return x + 3
}
function fn4(x) {
	return x + 4
}
function compose(...arg) {
    let arr = arg
    return arr.reduce((prev, next) => {
            return (num) => {
              return prev(next(num))
            }
    })
}
let a = compose(fn1, fn2, fn3, fn4)
console.log(a(1))

2、基于setTimeout实现setInterval

function test() {
    console.log('3333333')
}
function mySetInterval(fn, delay = 1000) {
    let timer = null
    let interval = () => {
        fn()
        timer = setTimeout(interval, delay)
    }
    timer = setTimeout(interval, delay)
    return {
        cancle: () => clearTimeout(timer)
    }
}
mySetInterval(test)

3、setInterval模拟实现setTimeout

function test() {
    console.log('3333333333')
}

function mySetTimeout(fn, delay = 1000) {
    let timer = null
    timer = setInterval(() => {
        clearInterval(timer)
        fn()
    }, delay)
}
mySetTimeout(test)

4、实现发布订阅模式

class EventEmitter{
    constructor() {
        this.cache = {}
    }

    on(type, fn) {
        if(!this.cache[type]) this.cache[type] = []
        this.cache[type].push(fn)
    }

    off(type, fn) {
        if(!this.cache[type]) return
        if(!fn) {
                this.cache[type] = []
        }else {
                this.cache[type] = this.cache[type].filter(item => item !== fn)
        }  
    }

    emit(type, ...arg) {
        if(!this.cache[type]) return
        this.cache[type].forEach(item => item(...arg))
    }

    once(type, fn) {
        const fnNew = () => {
                fn()
                this.off(type, fnNew)
        }
        this.on(type, fnNew)
    }
}

5、数组去重(方法很多,这里只写一种)

function uniqueArr(arr) {
    return [...new Set(arr)]
}

console.log(uniqueArr([1,2,3,5,5,6,6]))

6、数组扁平化

const isHasArr = (arr) => arr.some(item => Array.isArray(item))

function flatter(arr, count) {
    let i = 0
    while(isHasArr(arr) && (!count || i < count)) {
            arr = [].concat(...arr)
            i++
    }	
    return arr
}
console.log(flatter([1,2,3,[1,2,[2, [5]]]]))

7、寄生组合式继承

function Parent(name) {
    this.name = name
    this.say = function () {
            console.log(`我是${this.name}, 今年${this.age}岁`)
    }
}

function Child(name, age) {
    Parent.call(this, name)
    this.age = age
}

Child.prototype = Object.create(Parent.prototype)

Child.prototype.constructor = Child

const child = new Child('张三', 18)

child.say()

8、实现一个promise调度器

class Scheduler{
    constructor(limit) {
        this.limit = limit
        this.taskQueue = []
        this.startTaskCount = 0
    }

    add(time, info) {
        const fn = () => {
            return new Promise((rsolve, reject) => {
                    setTimeout(() => {
                            console.log(info)
                            rsolve()
                    }, time)
            }) 
        }
        this.taskQueue.push(fn)
    }

    startTask() {
        for(let i = 0; i < this.limit; i++) {
                this.request()
        }
    }

    request() {
        if(this.startTaskCount >= this.limit || this.taskQueue.length < 1) return
        this.startTaskCount++
        this.taskQueue.shift()().then(() => {
                this.startTaskCount--
                this.request()
        })
    }
}

const scheduler = new Scheduler(2)
scheduler.add(1000, "1")
scheduler.add(500, "2")
scheduler.add(300, "3")
scheduler.add(400, "4")
scheduler.startTask()

9、实现new操作符

function myNew(Fn, ...arg) {
    let obj = Object.create(null)
    obj.__proto__ = Fn.prototype
    let result = Fn.call(obj, ...arg)
    return (typeof result === 'object' && result !== null) || typeof result === 'function' ? result : obj
}

10、深度克隆

function deepClone(obj) {
    if(typeof obj !== 'object' || obj === null) {
        return obj
    }else if(obj instanceof Set) {
        let set = new Set()
        obj.forEach(item => {
            set.add(deepClone(item))
        })
        return set
    }else if(obj instanceof Map) {
        let map = new Map()
        obj.forEach((item, key) => {
            map.set(key, deepClone(item))
        })
        return map
    }else if(obj instanceof RegExp) {
        return new RegExp(obj)
    }else if(obj instanceof Date) {
        return new Date(obj)
    }else {
        let cloneObj = Array.isArray(obj) ? [] : {}4
        for(let key in obj) {
            if(obj.hasOwnProperty(key)) {
                cloneObj[key] = deepClone(obj[key])
            }
        }
        return cloneObj
    }
}

11、实现instanceof

function myInstanceof(child, parent) {
    while(child) {
        if(child.__proto__ === parent.prototype) return true
        child = child.__proto__
    }
    return false
}

function Test() {}
let test = new Test()
console.log(myInstanceof(test, Test))

12、函数柯里化

function fn(a, b, c, d) {
    return a + b + c + d
}

function currying(fn, ...arg) {
    let args = [...arg]
    const result = (...Arg) => {
        args = [...args, ...Arg]
        if(args.length >= fn.length) {
                return fn(...args)
        }
        return result
    }
    return result
}
let fn1 = currying(fn, 1,2)
console.log(fn1(3,5, 7))

13、实现LazyMan函数

function LazyMan(name) {
	return new _LazyMan(name)
}

class _LazyMan{
    constructor(name) {
        this.name = name
        this.taskQueue = []
        const fn = () => {
                console.log(`Hi! This is ${this.name}`)
                this.next()
        }
        this.taskQueue.push(fn)
        Promise.resolve().then(() => {
                this.next()
        })
    }

    next() {
        if(!this.taskQueue.length) return
        this.taskQueue.shift()()
    }

    eat(food) {
        const fn = () => {
                console.log(`Eat ${food}~`)
                this.next()
        }
        this.taskQueue.push(fn)
        return this
    }

    sleep(s) {
        this.timeFn(10, true)
        return this
    }

    sleepFirst(s) {
        this.timeFn(5, false)
        return this
    }

    timeFn(s, flag) {
        const fn = () => {
                setTimeout(() => {
                        console.log(`Wake Up after ${s}秒`)
                        this.next()
                }, s*1000)
        }
        if(flag) {
                this.taskQueue.push(fn)
        }else {
                this.taskQueue.unshift(fn)
        }
    }

}

// LazyMan('Hank')
// Hi! This is Hank!

// LazyMan('Hank').sleep(10).eat('dinner')
// Hi! This is Hank!
//等待10秒..
// Wake up after 10
// Eat dinner~

// LazyMan('Hank').eat('dinner').eat('supper')
// Hi This is Hank!
// Eat dinner~
// Eat supper~

// LazyMan('Hank').eat('supper').sleepFirst(5)
//等待5秒
// Wake up after 5
// Hi This is Hank!
// Eat supper

14、版本排序的方法

function MySort(arr) {
    arr.sort((a, b) => {
        let i = 0
        let arr1 = a.split('.')
        let arr2 = b.split('.')
        while(true) {
            let s1 = arr1[i]
            let s2 = arr2[i]
            i++

            if(s1 === undefined || s2 === undefined) return arr2.length - arr1.length	
            if(s1 === s2) continue

            return s2 - s1
        }
    })
    return arr
}

15、LRU缓存

class LRUCache{
    constructor(limit) {
        this.limit = limit
        this.map = new Map()
    }

    get(key) {
        if(!this.map.has(key)) return -1
        let tempValue = this.map.get(key)
        this.map.delete(key)
        this.map.set(key, tempValue)

        return tempValue
    }

    put(key, value) {
        if(this.map.has(key)) {
            this.map.delete(key)
            this.map.set(key, value)
        }else {
            if(this.map.size === this.limit) {
                this.map.delete(this.map.keys().next().value)
                this.map.set(key, value)
            }else {
                this.map.set(key, value)
            }
        }
    }
}

16、实现一个add方法

function add(...arg) {
    let args = [...arg]
    const fn = (...Arg) => {
            args = [...args, ...Arg]
            return fn
    }

    fn.toString = () => {
            if(!args.length) return
            return args.reduce((prev, curr) => prev + curr, 0)
    }

    return fn
}

console.log(add(1,2,3)(4)()==10)

17、动态规划求解硬币找零

function coinChange(coins, amount) {
    if(coins.length < 1) return -1
    let dp = []
    dp[0] = 0
    let len = coins.length
    for(let i = 1; i <= amount; i++){
        dp[i] = Infinity
        for(let j = 0; j < len; j++) {
             if(i >= coins[j]) {
                dp[i] = Math.min(dp[i], dp[i - coins[j]] + 1)
             }
        }
    }
    if(dp[amount] === Infinity) return -1
    return dp[amount]
};
console.log(coinChange([1, 2, 5], 11))

18、请实现DOM2JSON一个函数,可以把一个DOM节点输出JSON格式

function dom2Json(domtree) {
    let obj = {}
    obj.name = domtree.tagName
    obj.children = []
    domtree.children.forEach(item => obj.children.push(dom2Json(item)))

    return obj
}

19、实现json格式数据转dom

function _render(vnode) {
    if(typeof vnode === 'number') vnode = String(vnode)
    if(typeof vnode === 'string') return document.createTextNode(vnode)
    const dom = document.createElement(vnode.tag)
    if(vnode.attrs) {
        let keys = Object.keys(vnode.attrs)
        keys.forEach(key => dom.setAttribute(key, vnode.attrs[key]))

    }
    if(vnode.children && Array.isArray(vnode.children)) {
        vnode.children.forEach(item => dom.appendChild(_render(item)))
    }
    return dom
}

20、实现模板字符串解析

let template = "我是{{name}},年龄{{age}},性别{{sex}}";
let data = {
  name: "张三",
  age: 18,
	sex: '男'
};

function render(template, data) {
    const computed = template.replace(/\{\{(\w+)\}\}/g, function (match, key) {
            return data[key]
    })

    return computed
}
console.log(render(template, data))

21、对象扁平化

const isObject = (obj) => typeof obj === 'object' && obj !== null

const isArray = (arr) => Array.isArray(arr)

function flatten(obj) {
    let newObj = {}
    const fn = (value, str) => {
        if(!isObject(value)) {
            let newStr = str + ''
            newObj[newStr] = value
            return
        }
        for(let key in value) {
            if(isArray(value)) {
                    fn(value[key], str + `[${key}]`)
            }else {
                    fn(value[key], str === '' ? str + `${key}` : str + `.${key}`)
            }
        }

    }
    fn(obj, '')
    return newObj
}
const obj = {
    a: {
        b: 1,
        c: 2,
        d: {e: 5}
    },
    b: [1, 3, {a: 2, b: 3}],
    c: 3
}
 console.log(flatten(obj))

22、列表转成树

function listToTree(data) {
    let map = {}
    let tree = []
    data.forEach(item => map[item.id] = item)
    data.forEach(item => {
            if(map[item.parentId]) {
                    (map[item.parentId].children || (map[item.parentId].children = [])).push(item)
            }else {
                    tree.push(item)
            }
    })

    return tree
}

let arr = [
    {
        id: 1,
        text: '节点1',
        parentId: 0 //这里用0表示为顶级节点
    },
    {
        id: 2,
        text: '节点1_1',
        parentId: 1 //通过这个字段来确定子父级
    }
]
console.log(listToTree(arr))

23、树形结构转成列表

function treeToList(data) {
    let arr = []

    const fn = (tree) => {
            tree.forEach(item => {
                    arr.push(item)
                    if(item.children) {
                            fn(item.children)
                            delete item.children
                    }
            })
    }

    fn(treeData)
    return arr
}
let treeData = [
    {
        id: 1,
        text: '节点1',
        parentId: 0,
        children: [
            {
                id:2,
                text: '节点1_1',
                parentId:1
            }
        ]
    }
]
console.log(treeToList(treeData))

24、大数相加

function add(a, b) {
    let maxLength = Math.max(a.length, b.length)
    let t = 0
    let f = 0
    let sum = ''
    a = a.padStart(maxLength, 0)
    b = b.padStart(maxLength, 0)
    for(let i = maxLength - 1; i >= 0; i--) {
        t = parseInt(a[i]) + parseInt(b[i]) + f
        f = Math.floor(t / 10)
        sum = (t % 10) + sum
    }
    if(f !== 0) {
        sum = '' + f + sum
    }
    return sum
}
let a = "9007199254740991"
let b = "1234567899999999999"

console.log(add(a, b))

25、两数相加

function intersect(num1, num2) {
    const len1 = num1.length
    const len2 = num2.length
    num1.sort((a, b) => a - b)
    num2.sort((a, b) => a - b)
    let res = []
    let i = 0
    let j = 0
    while(i < len1 && j < len2) {
        if(num1[i] === num2[j]) {
            res.push(num1[i])
            i++
            j++
        }else if(num1[i] < num2[j]) {
            i++
        }else {
            j++
        }
    }
    return res
}
let m1 = [4, 9, 5]
let m2 = [9, 4, 9, 8, 4]
let n1 = [1, 2, 2, 1]
let n2 = [2, 2]
console.log(intersect(m1, m2))
console.log(intersect(n1, n2))