手写题总结--持续更新

128 阅读7分钟

自用记录,不保证都对

手写applyMiddlewares

  1. 题目要求
  function rawMethod(a){
    return a+1
  }
  function middleware1(next){
    return function(a){
        console.log('middleware1======')
        return next(a)+1
    }
  }
  function middleware2(next){
    return function(a){
        console.log('middleware2======')
        return next(a)+1
    }
  }
  function middleware3(next){
    return function(a){
        console.log('middleware3======')
        return next(a)+1
    }
  }
  var newMethod = applyMiddleWare(rawMethod,middleware3,middleware2)
  var x = newMethod(1) // 要求输出 middleware2=>middleware3=>rawMethod
  console.log(x) // 3
  var newMethod = applyMiddleWare(newMethod,middleware1)
  var y = newMethod(10) // 要求输出 middleware1=>middleware2=>middleware3=>rawMethod 
  console.log(y)// 13
  
  1. 代码实现
function applyMiddleWare(){
    const _fn = arguments[0]
    const _middles = Array.prototype.slice.call(arguments,1)
    let _temp = _fn
    for(let i = 0; i<_middles.length;i++ ){
        _temp = _middles[i](_temp)
    }
    function _outputFn1(n){
        return _temp(n)-1
    }
    _outputFn1.__apply = true
    function _outputFn2(n){
        return _temp(n)
    }
    _outputFn2.__apply = true
    if(_fn.__apply){
        return _outputFn2
    }else {
        return _outputFn1
    }
  }

手写call

Function.prototype.myCall = function(ctx,...args){
    var context = ctx==null?globalThis: Object(ctx)
    var key = Symbol('temp')
    Object.defineProperty(context,key,{
        enumerable: false,
        value: this
    })
    var result = context[key](...args)
    delete context[key] 
    return result

}

手写bind

Function.prototype.mybind = function(ctx){
    let args = Array.prototype.slice.call(arguments,1)
    let fn = this
    return function A(){
        let restArgs = Array.prototype.slice.call(arguments)
        let allArgs = args.concat(restArgs)
        if(Object.getPrototypeOf(this)===A.prototype){
            return new fn(...allArgs)
        }else{
            fn.apply(ctx,allArgs)
        }
    }
}

new 做了什么

function create(fn,...args){
    var obj = {}
    Object.setPrototypeOf(obj,fn.prototype)
    var result = fn.apply(obj,args)
    return result instanceof Object?result: obj
}

深度优先遍历(dfs)

  1. 题目
const data = {
    name: 'A',
    children: [
        {
            name: 'B',
            children: [
                {
                    name: 'D'
                },
                {
                    name: 'E'
                }
            ]
        },
        {
            name: 'C',
            children: [
                {
                    name: 'F'
                },
                {
                    name: 'G'
                }
            ]
        }
    ]
  }
  1. 代码实现
 function DFS(data){
    if(!data){
        return
    }
    console.log(data?.name)
    if(data.children && data.children.length>0){
        data.children.forEach(item=>{
            DFS(item)
        })
    }
  }
  // 查找子节点
 console.log(findItem(data, 'G'))
function findItem(root, target){
    if(!root){
        return
    }   
    if(root.name === target){
        return root
    }
    if(root.children&& root.children.length>0){
        for(let i = 0; i< root.children.length; i++){
            const res = findItem(root.children[i],target)
            if(res){
                return res
            }
        }
    }
}

广度优先遍历 (bfs)

function BFS(data){
    const stack = [data]
    while(stack.length){
        const node = stack.shift()
        console.log(node.name)
        if(node.children && Array.isArray(node.children)){
            node.children.forEach(item=>{
                stack.push(item)
            })
        }
    }
  }

vue2的响应式方法

  1. 对象
const person = {
    name: 'lily',
    age: 18,
    hobbits: ['dance','sing'],
}
function reactive(obj){
    for(let key in obj) {
        Object.defineProperty(obj,key,{
            get: function(){
                console.log('get====',key)
            },
            set: function(value){
                console.log('set======',key,value)
            }
        })
    }
}
reactive(person)
console.log(person.age)
console.log(person.age=5,person.age)
  1. 数组
const newArrProto = Object.create(Array)
        ['push','pop','slice','splice','sort','shift','unshift'].forEach(element => {
    // newArrProto.prototype[element] = function(){
    //     console.log('element=========', element)
    //     Array.prototype[element].call(this,arguments)
    // }
})
const a = []
a.push('kkk')
console.log(a)

vue3的响应式方法

function reactive(obj){
    if(typeof obj !=='object'){
        return
    }
    return new Proxy(obj,{
        get(target,key,receiver){
            console.log('get====',target,key)
            return Reflect.get(...arguments)
        },
        set(target,key,value,receiver){
            console.log('set===',target,key,value)
            return  Reflect.set(...arguments)
        },
        deleteProperty(target,key){
            console.log('deleteProperty=======',target,key)
            return Reflect.deleteProperty(...arguments)
        }
    })
}
let arr = ['1','2','3','4','5']
const arrProxy = reactive(arr)
console.log('arrProxy=======',arrProxy)
arrProxy.push('6')
arrProxy.pop()
arrProxy[6] = '9999'

柯里化函数

  1. 题目
function add(a, b, c) {
  return a + b + c
}
const sum = curring(add,1);
console.log(sum(2,3));
console.log(sum(2)(3));
  1. 代码
    function curring(fn){
        let args = Array.prototype.slice.call(arguments,1)
        return function(){
            let restArgs = Array.prototype.slice.call(arguments)
            let allArgs = args.concat(restArgs)
            if(fn.length<=allArgs.length){
                return fn.apply(this, allArgs)
            }else {
                return curring(fn, ...allArgs)
            }
        }
    }

compose函数

function add1(str) {
	return 1 + str;
}
function add2(str) {
	return 2 + str;
}
function sum(a, b) {
	return a + b;
}
// add1(add2(sum(a,b)))
function compose(...funcs){
    if(funcs.length === 0){
        return args=>args
    }
    if(funcs.length === 1){
        return funcs[0]
    }
    return funcs.reduce((a,b)=>{
        return (...args)=>a(b(...args))
    })
}

instanceOf

 function instanceofFn(left,right){
    if(typeof A !== 'object' || A === null || typeof B !=='function'){
        return false
    }
    while(true){
        if(left === null){
            return false
        }
        if(left.__proto__ === right.prototype){
            return true
        }
        left = left.__proto__
    }
}

lazyman

  1. 题目
// 实现一个 LazyMan 方法

// 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”).sleepFirst(5).eat(“supper”)输出
// //等待5秒
// Wake up after 5
// Hi! This is Hank!
// Eat supper
  1. 代码
class lazyMan {
    constructor(name){
      this.name = name
      this.promiseQueue=[]
      this.callName()
      this.walk()
    }
    callName = function(){
        let fn = ()=>{
            console.log('Hi! This is' + this.name)
            return Promise.resolve();
        }
        this.promiseQueue.push(fn)
        return this
    }
    walk = function(){
     let  promiseResolve = Promise.resolve()
      setTimeout(()=>{
        this.promiseQueue.forEach((item)=>{
          promiseResolve = promiseResolve.then(item)
        })
      },0)
    }
    sleep = (time)=>{
      let fn = ()=>{
        return new Promise((resolve)=>{
          setTimeout(()=>{
            console.log('Wake up after '+ time)
            resolve()
          },time*1000)
        })
      }
      this.promiseQueue.push(fn)
      return this
    }
    eat = (value)=>{
      var fn = function(){
        console.log("Eat " + value)
        return Promise.resolve()
      }
      this.promiseQueue.push(fn)
      return this
    }
    sleepFirst = (time)=>{
      var fn = function(){
        return new Promise(function(resolve){
          setTimeout(function(){
            console.log('Wake up after'+ time)
            resolve()
          }, time * 1000)
          
        })
      }
      this.promiseQueue.unshift(fn)
      return this
    }
  }
  function LazyMan(name){
    return new lazyMan(name)
  }
  LazyMan("Hank").sleep(5).eat('supper')
// LazyMan("Hank").sleepFirst(5).eat('supper')

深拷贝

  1. 拷贝目标
/*
    实现深拷贝
    1。 判断循环引用
    2. 判断正则对象
    3. 判断日期对象
    4. 属性对象直接进行递归拷贝
    5. 考虑拷贝时不能丢失原本对象的原型继承关系
    6. 考虑拷贝时的属性修饰符
  */
  1. 代码实现
function deepCopy(value) {
      var weakMap = new WeakMap()
      function _deepCopy(value){
           // 如果value是普通类型 直接返回
          if( value instanceof Date) {
            return new Date(value.valueOf())
          } 
          if( value instanceof RegExp) {
            return new RegExp(value.valueOf())
          } 
          if (typeof value !== 'object' || value === null) {
            return value
          }
          if(weakMap.has(value)){
            return weakMap.get(value)
          }
          // // 考虑对象的原型 获得原本对象的原型 创建一个新的对象继承这个对象的原型
          const prototype = Object.getPrototypeOf(value)
          // 考虑拷贝时不能 丢失对原有对象的属性描述符 
          const description = Object.getOwnPropertyDescriptors(value)
          // 创建新的空对象 同时继承原有对象原型 同时拥有对应的描述符
          let result = Object.create(prototype, description)
          // 遍历对象的属性 进行拷贝 Reflect.ownKeys 遍历获取自身的不可枚举以及key为Symbol的属性
          result = Array.isArray(value) ? []:  {}
          weakMap.set(value, result)
          for(var key in value) {
            if(value.hasOwnProperty(key)) {
              result[key] = _deepCopy(value[key])
            }
          }
          return result
        }
        return _deepCopy(value)
    }
    // const newObj = deepCopy(obj1)
    // console.log(newObj)
    // console.log(newObj !== obj1)
    // console.log(newObj.loop !== obj1.loop)
    // console.log(newObj.customArr[3] !== obj1)
    // console.log(newObj.customArr[3] === newObj)

promise拦截器

  1. 完全串形执行,按顺序输出
  2. 并行执行,按顺序输出
        let i = 0
        const createPromise = (num) => new Promise((resolve, reject) => setTimeout(function(){
            resolve(i++)
        }, num*1000))
        // 完全串形执行,按顺序输出
        function runOneByOne(promises) {
            if(!Array.isArray(promises) || promises.length === 0){
                return Promise.resolve([])
            }
            return new Promise((resolve,reject)=>{
                let arr = []
                const runTask = function(){
                    console.log('promises===', promises)
                    if(promises.length === 0 ) {
                        return  resolve(arr)
                    }
                    const task = promises.shift()
                    task().then((res)=>{
                        console.log('res===', res)
                        arr.push(res)
                        runTask()
                    }).catch(err=>{
                        runTask()
                    })
                }
                runTask()
            })

        }
        // 并行执行,串形按顺序输出
        function runOneByOne2(promises) {
            if(!Array.isArray(promises) || promises.length === 0){
                return Promise.resolve([])
            }
            return new Promise((resolve,reject)=>{
                let i = 0
                let result = []
                function handleResult(index,res){
                    if(index === i){
                        i++
                        while(result[i] !=null){
                            i++
                        }
                    }else{
                        result[index] = res
                    }
                    if(i ===promises.length ){
                        console.log('i', i)
                        resolve()
                    }
                }
                for(let i = 0; i<promises.length; i++){
                    promises[i](4-i).then((res)=>{
                        handleResult(i,res)
                    }).catch(err=>{
                        console.log('err')
                    })
                }
            })

        }
        const promises = [createPromise, createPromise, createPromise, createPromise]

        console.time('run')
        runOneByOne2(promises)
        .then(res => {
            console.timeEnd('run')
            console.log('全部执行结束', res)
        })

对象转a.b.c.dd格式

// 输入
const entry={
    a: {
      b: { 
        c: {
          dd: "abcdd"
        }
      },
      d: {
        x: "adxx"
      }
    }
  }
const output = {
    "a.b.c.dd": "abcdd",
    "a.d.xx": "adxx",
};
// 输出
function transferObj(obj){
    let result = {}

    const parse = (data,parentKey)=>{
        if(typeof data === 'string'){
            result[parentKey] = data
        }
        if(typeof data === 'object'){
            for(let key in data){
                parse(data[key],(parentKey?parentKey+'.':parentKey)+key)
            }
        }
    }
    parse(obj,'')
    return result
}
console.log(transferObj(entry))

a.b.c.dd格式转对象

// 输入
const input = {
    "a.b.c.dd": "abcdd",
    "a.d.xx": "adxx",
};
// 输出
const output={
    a: {
      b: { 
        c: {
          dd: "abcdd"
        }
      },
      d: {
        x: "adxx"
      }
    }
  }
function transferObj(obj){
    if(typeof obj !== 'object'){
        return
    }
    let result = {}
    for(let key in obj){
        let keyArr = key.split('.')
        let temp = result
        for(let i = 0; i< keyArr.length; i++){
            if(i === keyArr.length - 1){
                temp[keyArr[i]] = obj[key]
            }else{
                temp[keyArr[i]] = temp[keyArr[i]] || {}
                temp =  temp[keyArr[i]]
            }
        }
    }
    return result
}

环形杀人

环形100个人,0-99每隔3个人杀一个人,从第0开始(比如下标为0和为4的人会被杀掉)问最终剩下哪3个人。对应人的位置或者写出代码均可。

function loopKill(){
    let arr = []
    for(let i = 0; i< 100; i++){
        arr[i] = i
    }
    const deepKill = (arr,index)=>{
        while(index<arr.length && arr.length>3){
            let num = arr.splice(index,1)
            index+=3
        }
        if(arr.length>3){
            deepKill(arr,index-arr.length)
        }else if(arr.length===3){
            return arr
        }
    }
    deepKill(arr,0)
}
loopKill()

proxy代理输出路径

  1. 题目
// 题目:实现一个 proxyObj 方法,输出符合预期
const a = {
  b: 1,
  c: {
    d: 2,
  }
};

function proxyObj(obj) {
  // code here
}

const proxyA = proxyObj(a);

console.log(proxyA.b);
// 输出 ‘b’

console.log(proxyA.c.d);
// 输出 ’c.d‘
  1. 代码实现
  function proxyObj(obj,parentkey) {
    return new Proxy(obj,{
        get(target,prop){
            let currentKey = parentkey?`${parentkey}.${prop}`:prop
            if(typeof target[prop] === 'object'){
                return proxyObj(target[prop],currentKey)
            }else{
                return currentKey
            }
        }
    })
  }

proxy 链式调用

  1. 题目
 function increase(a){
    return a + 1
}
function decrease(a){
    return a - 1
}
function double(a){
    return 2 * a
}
console.log(chain(3).increase.double.end) // 输出8
console.log(chain(2).decrease.double.end) // 输出2
  1. 代码实现
// 写法一
 function chain(value){
    const proxy = new Proxy({value},{
        get(obj, prop){
            if(typeof window[prop] === 'function'){
                obj.value =  window[prop](obj.value)
                return proxy
            }else if(prop === 'end'){
                return obj.value
            }
        }
    })
    return proxy
}
// 写法二
const chain = (function(){
    return function(value){
        let fnArr = []
        const proxy = new Proxy({value},{
            get(obj, prop){
                if(prop === 'end'){
                    console.log(fnArr)
                    return fnArr.reduce((prev,curr)=>{
                        return curr(prev)
                    },value)
                }
                fnArr.push(window[prop])
                return proxy
            }
        })
        return proxy
    }
})()

打印二维数组成三角形格式

  1. 题目
二位数组,对角线依次打印所有元素。
[
    [1,2,3,4],
    [2,3,4,5],
    [3,4,5,6],
    [4,5,6,7]
] 
输出,从左上角开始,到右下角
1
2 2
3 3 3 
4 4 4 4 
5 5 5
6 6 
7 
  1. 代码实现
let arr = [[1,2,3,4],[2,3,4,5],[3,4,5,6],[4,5,6,7]]
function log(arr){
    if(!Array.isArray(arr) || arr.length ===0){
        return ''
    }
   let str = ''
   let ln = arr.length-1
   let max = ln*2+1
   let count = 0
   while(count<max){
        let row = count> ln ? ln : count
        let col = count> ln ? count - ln : 0
        while(row>=0&&col<=ln){
            str+=arr[row][col]
            row--
            col++
        }
        str+='\n'
        count++
   }
   return str
}
console.log(log(arr))

手动实现Array.prototype.map方法

Array.prototype.myMap = function(fn){
    if(typeof fn !== 'function'){
        throw new Error('first params must be a function') 
    }
    if(!Array.isArray(this)){
        throw new Error('array error') 
    }
    let arr = this
    let result = []
    for(let i = 0; i< arr.length; i++){
        let value = fn(arr[i],i,arr)
        result.push(value)
    }
    return result
}

手动实现Array.prototype.filter方法

if(typeof fn !== 'function'){
        throw new Error('first params must be a function') 
    }
    if(!Array.isArray(this)){
        throw new Error('array error') 
    }
    let arr = this
    let result = []
    for(let i = 0; i< arr.length; i++){
        let value = fn(arr[i],i,arr)
        if(value){
            result.push(arr[i])
        }
    }
    return result

手动实现Array.prototype.reduce方法

Array.prototype.myReduce = function(fn,initial){
    if(typeof fn !== 'function'){
        throw new Error('first params must be a function') 
    }
    if(!Array.isArray(this)){
        throw new Error('array error') 
    }
    let arr = this
    let prev = initial !== undefined ? initial : arr[0]
    let min = initial !== undefined ? 0 : 1
    for(let i = min; i< arr.length; i++){
        prev = fn(prev,arr[i],i,arr)
    }
    return prev
}