前端手写题

80 阅读1分钟

数组转树


// interface IArrayItem {
//     id: number;
//     name: string;
//     parentId: number;
// }

// interface ITreeNode{
//     id: number;
//     name: string;
//     children?: ITreeNode[]
// }

// function covert(arr: IArrayItem[]): ITreeNode | null{
//     let root = null;

//     const idToTreeNode: Map<number, ITreeNode> = new Map()

//     arr.forEach((item: IArrayItem) => {
//         const { id,  name, parentId } = item;
//         const treeNode: ITreeNode = {
//             id,
//             name
//         }

//         idToTreeNode.set(id, treeNode)

//         const parentNode = idToTreeNode.get(parentId);

//         if(parentNode){
//             if(parentNode.children === null) parentNode.children = [];
//             parentNode.children?.push(treeNode)
//         }

//          // 找到根节点
//          if (parentId === 0) root = treeNode
//     })
//     return root;
// }

interface IArrayItem {
    id: number;
    name: string;
    parentId: number;
}

interface ITreeNode {
    id: number;
    name: string;
    children?: ITreeNode[];
}
function covert(arr: IArrayItem[]): ITreeNode | null {
    let root = null;

    let map: Map<number, ITreeNode> = new Map();

    arr.forEach(item => {
        const { id, name, parentId } = item;
        let treeNode = { id, name };

        map.set(id, treeNode)

        const parentNode = map.get(parentId);
        if(parentNode){
            if(parentNode.children === null) parentNode.children = [];

            parentNode.children?.push(treeNode)
        }
        if(parentId === 0) root = treeNode
    })

    return root;
}

const arr = [
    { id: 1, name: '部门A', parentId: 0 }, // 0 代表顶级节点,无父节点
    { id: 2, name: '部门B', parentId: 1 },
    { id: 3, name: '部门C', parentId: 1 },
    { id: 4, name: '部门D', parentId: 2 },
    { id: 5, name: '部门E', parentId: 2 },
    { id: 6, name: '部门F', parentId: 3 },
]
const tree = covert(arr)
console.info(tree)

并行请求

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <body>
    <script>
      var urls = [1, 2, 3, 4, 5];

     
      function multiRequest(urls = [], maxNum){
        let len = urls.length;
        let result = new Array(len).fill(1)

        let count = 0;

        return new Promise((resolve, reject) => {
          if(count < maxNum){
            next()
          }

          function next(){
            let current = count++

            if(current >= len){
              resolve(result)
              return;
            }

            const url = urls[current]

            fetch(url).then(res => {
              result[current] = res;

              if(current < len){
                next()
              }
            }, err => {
              result[current] = err;

              if(current < len){
                next()
              }
            })
          }
        })
      }

      function multiRequest(urls = [], maxNum) {
        // 请求总数量
        const len = urls.length;
        // 根据请求数量创建一个数组来保存请求的结果
        const result = new Array(len).fill(false);
        // 当前完成的数量
        let count = 0;

        return new Promise((resolve, reject) => {
          // 请求maxNum个
          while (count < maxNum) {
            next();
          }
          function next() {
            let current = count++;
            // 处理边界条件
            if (current >= len) {
              // 请求全部完成就将promise置为成功状态, 然后将result作为promise值返回
              resolve(result);
              return;
            }
            const url = urls[current];
            console.log(`开始 ${current}`, new Date().toLocaleString());
            fetch(url)
              .then((res) => {
                // 保存请求结果
                result[current] = res;
                console.log(`完成 ${current}`, new Date().toLocaleString());
                // 请求没有全部完成, 就递归
                if (current < len) {
                  next();
                }
              })
              .catch((err) => {
                console.log(`结束 ${current}`, new Date().toLocaleString());
                result[current] = err;
                // 请求没有全部完成, 就递归
                if (current < len) {
                  next();
                }
              });
          }
        });
      }

      console.log(multiRequest(urls, 2));
      //         var p = function () {
      //   return new Promise(function (resolve, reject) {
      //     setTimeout(() => {
      //       console.log('1000')
      //       resolve()
      //     }, 1000)
      //   })
      // }
      // var p1 = function () {
      //   return new Promise(function (resolve, reject) {
      //     setTimeout(() => {
      //       console.log('2000')
      //       resolve()
      //     }, 2000)
      //   })
      // }
      // var p2 = function () {
      //   return new Promise(function (resolve, reject) {
      //     setTimeout(() => {
      //       console.log('3000')
      //       resolve()
      //     }, 3000)
      //   })
      // }

      // p().then(() => {
      //   return p1()
      // }).then(() => {
      //   return p2()
      // }).then(() => {
      //   console.log('end')
      // })
      // var promises = function () {
      //   return [1000, 2000, 3000].map(current => {
      //     return new Promise(function (resolve, reject) {
      //       setTimeout(() => {
      //         console.log(current)
      //       }, current)
      //     })
      //   })
      // }

      // Promise.all(promises()).then(() => {
      //   console.log('end')
      // })
    </script>
  </body>
</html>

深度打平

function flattenDeep(arr: any[]): any[]{
    let res: any[] = [];

    arr.forEach(item => {
        if(Array.isArray(item)){
            const flatItem = flattenDeep(item);
            flatItem.forEach(n => res.push(n))
        }else{
            res.push(item)
        }
    })

    return res;
}

function flattenDeep2(arr: any[]): any[]{
    let res : any[]= [];
    arr.forEach(item => {
        if(Array.isArray(item)){
            const flatItem = flattenDeep2(item)
            flatItem.forEach(n => res.push(n))
        }else{
            res.push(item)
        }
    })
    return res;
}

判断类型


function getType(x: any): string{
    const originType = Object.prototype.toString.call(x);

    const spaceIndex = originType.indexOf(' ');
    const type = originType.slice(spaceIndex+1, -1);

    return type.toLowercase();
}

new

function customNew<T>(constructor: Function,...args: any[]): T{
    const obj = Object.create(constructor.prototype);

    constructor.apply(obj,args)
    return obj;
}

instanceof

function myInstanceof(instance: any, origin: any): boolean{

    if(instance === null) return false;

    const type = typeof instance;

    if(type !== 'object' && type !== 'function') return false;

    let tempInstance = instance;

    while(tempInstance){
        if(tempInstance.__proto__ === origin.prototype){
            return true;
        }

        tempInstance = tempInstance.__proto__
    }
    return false;
}

bind


// @ts-ignore
Function.prototype.customBind = function(context: any, ...bindArgs: any[]){
    const self = this;

    return function(...args: any[]){
        const newArgs = bindArgs.concat(args)
        return self.apply(context, newArgs)
    }
}

深克隆

function cloneDeep(obj: any){
    if(typeof obj !== 'object' || obj === null) return obj;

    let res: any;

    if(obj  instanceof Array){
        res = []
    }else {
        res = {};
    }

    for(let key in obj){
        if(obj.hasOwnProperty(key)){
            res[key] = cloneDeep(obj[key])
        }
    }

    return res;
}

function cloneDeep2(obj: any, map = new WeakMap()):any{
    if(typeof obj !== 'object' || obj === null) return obj;

    const objFromMap = map.get(obj)

    if(objFromMap) return objFromMap;

    let target: any = {};
    map.set(obj, target)

    if(obj instanceof Array){
        target = obj.map(item => cloneDeep2(item, map))
    }

    for(const key in obj){
        const val = obj[key];
        const val1 = cloneDeep2(val, map)
        target[key] = val1
    }

    if(obj instanceof Map){
        target = new Map()
        obj.forEach((v,k) => {
            const v1 = cloneDeep2(v,map)
            const k1 = cloneDeep2(k,map)
            target.set(k1,v1)
        })
    }

    if(obj instanceof Set){
        target = new Set()

        obj.forEach(v =>{
            const v1 = cloneDeep2(v,map)
            target.add(v1)
        })
    }

    return target;
}

大数之和

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <body>
    <script>
      let a = '9007199254740991';
      let b = '1234567899999999999';

      function add(a, b) {
        let maxLen = Math.max(a.length, b.length);
        a = a.padStart(maxLen, 0);
        b = b.padStart(maxLen, 0);

        let t = 0;
        let f = 0;
        let sum = '';

        for (let i = maxLen - 1; i >= 0; i--) {
          t = parseInt(a[i]) + parseInt(b[i]) + f;
          f = Math.floor(t / 10);
          sum = (t % 10) + sum;
        }

        if (f == 1) {
          sum = '1' + sum;
        }
        return sum;
      }
      function toThousands(num) {
        var result = [],
          counter = 0;
        num = (num || 0).toString().split('');
        console.log('ddd', num);
        for (var i = num.length - 1; i >= 0; i--) {
          counter++;
          result.unshift(num[i]);
          console.log('eee', result);
          if (!(counter % 3) && i != 0) {
            result.unshift(',');
          }
          console.log('fff', result);
        }
        return result.join('');
      }
      console.log(add(a, b));
      console.log(Number(add(a, b)));
      console.log(Number(add(a, b)).toLocaleString());
      console.log(toThousands(Number(add(a, b))));
    </script>
  </body>
</html>

event

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <script>
        class EventEmitter{
            constructor(){
                this.listeners = {};
            }

            on(type, cb){
                if(!this.listeners[type]){
                    this.listeners[type] = []
                }
                this.listeners[type].push(cb)
            }

            emit(type, ...args){
                if(this.listeners[type]){
                    this.listeners[type].forEach(cb => {
                        cb(...args)
                    })
                }
            }

            off(type,cb){
                if(this.listeners[type]){
                    const targetIndex = this.listeners[type].findIndex(item => item ===cb)
                    if(targetIndex !== -1){
                        this.listeners[type].splice(targetIndex,1)
                    }

                    if(this.listeners[type].length === 0){
                        delete this.listeners[type]
                    }
                }
            }

            once(type, cb){
                function newCb(...args){
                    cb(...args)
                    this.off(type, newCb)
                }
                this.on(type, newCb)
            }

            offAll(type){
                if(this.listeners[type]){
                    delete this.listeners[type]
                }
            }
        }
    </script>
</body>
</html>

观察者模式

class Subject {

    constructor() {
      this.observerList = [];
    }
  
    addObserver(observer) {
      this.observerList.push(observer);
    }
  
    removeObserver(observer) {
      const index = this.observerList.findIndex(o => o.name === observer.name);
      this.observerList.splice(index, 1);
    }
  
    notifyObservers(message) {
      const observers = this.observerList;
      observers.forEach(observer => observer.notified(message));
    }
  
  }
  
  class Observer {
  
    constructor(name, subject) {
      this.name = name;
      if (subject) {
        subject.addObserver(this);
      }
    }
  
    notified(message) {
      console.log(this.name, 'got message', message);
    }
  
  }
  
  function main() {
    const subject = new Subject();
    const observerA = new Observer('observerA', subject);
    const observerB = new Observer('observerB', subject);
    subject.notifyObservers(`Hello from subject at ${new Date()}`);
    console.log('------------------------')
  
    setTimeout(() => {
      const observerC = new Observer('observerC');
      const observerD = new Observer('observerD');
      subject.addObserver(observerC);
      subject.addObserver(observerD);
      subject.notifyObservers(`Hello from subject at ${new Date()}`);
      console.log('------------------------')
    }, 1000)
  
    setTimeout(() => {
      subject.removeObserver(observerA);
      subject.notifyObservers(`Hello from subject at ${new Date()}`);
      console.log('------------------------')
    }, 2000)
  }
  
  main();
  
  // observerA got message Hello from subject at Fri Jun 25 2021 16:25:09 GMT+0800 (GMT+08:00)
  // observerB got message Hello from subject at Fri Jun 25 2021 16:25:09 GMT+0800 (GMT+08:00)
  // ------------------------
  // observerA got message Hello from subject at Fri Jun 25 2021 16:25:10 GMT+0800 (GMT+08:00)
  // observerB got message Hello from subject at Fri Jun 25 2021 16:25:10 GMT+0800 (GMT+08:00)
  // observerC got message Hello from subject at Fri Jun 25 2021 16:25:10 GMT+0800 (GMT+08:00)
  // observerD got message Hello from subject at Fri Jun 25 2021 16:25:10 GMT+0800 (GMT+08:00)
  // ------------------------
  // observerB got message Hello from subject at Fri Jun 25 2021 16:25:11 GMT+0800 (GMT+08:00)
  // observerC got message Hello from subject at Fri Jun 25 2021 16:25:11 GMT+0800 (GMT+08:00)
  // observerD got message Hello from subject at Fri Jun 25 2021 16:25:11 GMT+0800 (GMT+08:00)
  // ------------------------

PROMISE

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <script>



        function promiseAll3(promises){
            if(!Array.isArray(promises)){
                throw new Error('promises must is Array')
            }

            return new Promise((resolve, reject) => {
                let promiseLen = promises.length;
                let resolvedNum = 0;
                let resultValue = new Array(promiseLen);

                for(let i = 0 ;i<promiseLen;i++){
                    (function(i){
                        Promise.then(res => {
                            resultValue[i]= res;
                            resolvedNum++

                            if(resolvedNum === promiseLen){
                                resolve(resultValue)
                            }
                            
                        }, err => {
                            reject(err)
                        })
                    })(i)
                }
            })
        }

        function promiseAll(promises){
            if(!Array.isArray(promises)){
                throw new Error('promises 必须是 数组')
            }

            

            return new Promise((resolve, reject) => {
                let promisesLen = promises.length;
                let resolvedNum = 0;
                let resolvedValue = new Array(promisesLen)

                for(let i = 0;i<promisesLen;i++){
                    (function(i){
                        Promise.resolve(promises[i]).then(res => {
                            resolvedNum++
                            resolvedValue[i] = res;

                            if(resolvedNum === promisesLen){
                                return resolve(resolvedValue)
                            }
                        }, err => {
                            return reject(err)
                        }) 
                    })(i)
                }
            })
        }


        function promiseRace(promises){
            if(!Array.isArray(promises)){
                throw new Error('promises 必须是 数组')
            }

            return new Promise((resolve, reject) => {
                for(let i = 0;i<promises.length;i++){
                    Promise.resolve(promises[i]).then(res =>{
                        resolve(res)
                    }, err => {
                        reject(err)
                    })
                }
            })
        }
    </script>
</body>
</html>