前端 手写题

107 阅读5分钟

1 对象深浅拷贝

//浅拷贝

  1   Object.assign(target,source)
  2   es6对象扩展运算符
  
 //深拷贝
 //1  Json方法  
    // 不支持值为undefined、函数和循环引用的情况
    const cloneObj = JSON.parse(JSON.stringify(obj))
 //2 递归拷贝
 function deepClone(obj){
    if(!obj || typeof obj!=="object")return;
    let newObj=Array.isArray(obj)?[]:{}
    for(let key in obj){
        if(obj.hasOwnProperty(key)){
            newObj[key]=typeof obj[key]==="object"?deepClone(obj[key]):obj[key]
        }

    }
    return newObj;
 }

2 防抖

//定义:触发事件后在n秒内函数只能执行一次,如果在n秒内又触发了事件,则会重新计算函数执行时间
//案例:
    //搜索框搜索输入 只需用户最后一次输入完,再发送请求
    //手机号,邮箱验证输入检测  onchange oninput 事件
    //窗口大小 Resize 只需窗口调整完成后,计算窗口大小,防止重复渲染;


    const debounce=(fn,wait,immediate)=>{
        let timer=null;
        return function (...agrs){
            if(timer) clearTimeout(timer);
            if(immediate&&!timer){
                fn.call(this,args);
            }
            timer=setTimeout(()=>{
                fn.call(this,agrs)
            },wait)
        };
    };
    const betterFn=debounce(()=>console.log('fn 防抖执行了'),1000,true)
    document.addEventListener("scroll",betterFn)


3 节流

//定义:当持续触发事件时,保证隔间时间触发一次事件。
//1. 懒加载、滚动加载、加载更多或监听滚动条位置;
//2. 百度搜索框,搜索联想功能;
//3. 防止高频点击提交,防止表单重复提交;
function throttle(fn,wait){
    let pre = 0;
    return function(...args){
        let now = Date.now();
        if( now - pre >= wait){
            fn.apply(this,args);
            pre = now;
        }
    }
}
function handle(){
    console.log(Math.random());
}
window.addEventListener("mousemove",throttle(handle,1000));

4 promise


// MyPromise.js

// 先定义三个常量表示状态
const PENDING = 'pending';
const FULFILLED = 'fulfilled';
const REJECTED = 'rejected';

// 新建 MyPromise 类
class MyPromise {
  constructor(executor){
    // executor 是一个执行器,进入会立即执行
    // 并传入resolve和reject方法
    executor(this.resolve, this.reject)
  }

  // 储存状态的变量,初始值是 pending
  status = PENDING;

  // resolve和reject为什么要用箭头函数?
  // 如果直接调用的话,普通函数this指向的是window或者undefined
  // 用箭头函数就可以让this指向当前实例对象
  // 成功之后的值
  value = null;
  // 失败之后的原因
  reason = null;

  // 更改成功后的状态
  resolve = (value) => {
    // 只有状态是等待,才执行状态修改
    if (this.status === PENDING) {
      // 状态修改为成功
      this.status = FULFILLED;
      // 保存成功之后的值
      this.value = value;
    }
  }

  // 更改失败后的状态
  reject = (reason) => {
    // 只有状态是等待,才执行状态修改
    if (this.status === PENDING) {
      // 状态成功为失败
      this.status = REJECTED;
      // 保存失败后的原因
      this.reason = reason;
    }
  }

  then(onFulfilled, onRejected) {
    // 判断状态
    if (this.status === FULFILLED) {
      // 调用成功回调,并且把值返回
      onFulfilled(this.value);
    } else if (this.status === REJECTED) {
      // 调用失败回调,并且把原因返回
      onRejected(this.reason);
    }
  }
}

module.exports = MyPromise

手写promise

class MyPromise {
    constructor(executor) {
        const resolve = res => {
            console.log(res)
        }
        const reject = rej => {
            console.log(rej)
        }
        executor && executor(resolve, reject)
    }
}
const promise = new Promice((resolve, reject) => {
    resolve('aa')
    reject('err')

})
promise.then(value => {
    console.log('resolve', value)
}, reason => {
    console.log('reject', reason)
})

5 手写reduce

//不考虑第二个参数:

Array.prototype.reduce = function (cb) {
    const arr = this; //this就是调用reduce方法的数组
    let total = arr[0]; // 默认为数组的第一项
    for (let i = 1; i < arr.length; i++) {
      total = cb(total, arr[i], i, arr);
    }
    return total;
  };


//考虑第二个参数:
  Array.prototype.reduce = function (cb, initialValue) {
    const arr = this;
    let total = initialValue || arr[0];
    // 有初始值的话从0遍历,否则从1遍历
    for (let i = initialValue ? 0 : 1; i < arr.length; i++) {
      total = cb(total, arr[i], i, arr);
    }
    return total;
  };

6 数组扁平化


//1  
function flatten(arr){
    return arr.reduce((result,item)=>{
        return result.concat(Array.isArray(item)?flatten(item):item);
    },[])
}
//2
function flat(arr, depth = 1) {
    if (depth > 0) {
      // 以下代码还可以简化,不过为了可读性,还是....
      return arr.reduce((pre, cur) => {
        return pre.concat(Array.isArray(cur) ? flat(cur, depth - 1) : cur);
      }, []);
    }
    return arr.slice();
  }

7 数组去重,数组对象去重

数组

//1  利用 ES6 set 关键字:
const newArr = [...new Set(arr)]
// 或
const newArr = Array.from(new Set(arr))

const arr = [2,7,5,7,2,8,9];
console.log([...new Set(arr)]); // [2,7,5,8,9];

//2  利用 ES5 filter 方法:
function unique(arr) {
    return arr.filter((item, index, array) => {
       return array.indexOf(item) === index;
    });
}

对象


const list = [{age:18,name:'张三'},{age:18,name:'李四'},{age:18,name:'王五'}]
let hash = {};
const newArr = list.reduce((item, next) => {
    hash[next.age] ? '' : hash[next.age] = true && item.push(next);
    return item;
}, []);
console.log(newArr);

8 instanceof

function myInstanceof(target, origin) {
    if (typeof target !== "object" || target === null) return false;
    if (typeof origin !== "function")
      throw new TypeError("origin must be function");
    let proto = Object.getPrototypeOf(target); // 相当于 proto = target.__proto__;
    while (proto) {
      if (proto === origin.prototype) return true;
      proto = Object.getPrototypeOf(proto);
    }
    return false;
  }

9 数组排序

sort 排序

// 对数字进行排序,简写
const arr = [3, 2, 4, 1, 5]
arr.sort((a, b) => a - b)
console.log(arr) // [1, 2, 3, 4, 5]

// 对字母进行排序,简写
const arr = ['b', 'c', 'a', 'e', 'd']
arr.sort()
console.log(arr) // ['a', 'b', 'c', 'd', 'e']

冒泡排序

function bubbleSort(arr) {
  let len = arr.length
  for (let i = 0; i < len - 1; i++) {
    // 从第一个元素开始,比较相邻的两个元素,前者大就交换位置
    for (let j = 0; j < len - 1 - i; j++) {
      if (arr[j] > arr[j + 1]) {
        let num = arr[j]
        arr[j] = arr[j + 1]
        arr[j + 1] = num
      }
    }
    // 每次遍历结束,都能找到一个最大值,放在数组最后
  }
  return arr
}

//测试
console.log(bubbleSort([2, 3, 1, 5, 4])) // [1, 2, 3, 4, 5]

快速排序

//快排
function sortArray(nums) {
  quickSort(0, nums.length - 1, nums);
  return nums;
}

function quickSort(start, end, arr) {
  if (start < end) {
    const mid = sort(start, end, arr);
    quickSort(start, mid - 1, arr);
    quickSort(mid + 1, end, arr);
  }
}

function sort(start, end, arr) {
  const base = arr[start];
  let left = start;
  let right = end;
  while (left !== right) {
    while (arr[right] >= base && right > left) {
      right--;
    }
    arr[left] = arr[right];
    while (arr[left] <= base && right > left) {
      left++;
    }
    arr[right] = arr[left];
  }
  arr[left] = base;
  return left;
}

10 继承

ES5 继承(寄生组合继承)

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

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

// 测试
let xm = new Child('xiaoming', 12) 
console.log(xm.name) // xiaoming
console.log(xm.age) // 12
xm.eat() // xiaoming is eating

ES6 继承

class Parent {
  constructor(name) {
    this.name = name
  }
  eat() {
    console.log(this.name + ' is eating')
  }
}

class Child extends Parent {
  constructor(name, age) {
    super(name)
    this.age = age
  }
}

// 测试
let xm = new Child('xiaoming', 12) 
console.log(xm.name) // xiaoming
console.log(xm.age) // 12
xm.eat() // xiaoming is eating

实现1个 EventBus 类,至少拥有on,emit两个方法

    class EventBus {
        constructor() {
            this.msgList = {}
        }
        on(msgName, fn) {
            // 首先判断消息是不是保存过
            if (this.msgList.hasOwnProperty(msgName)) {
                // 如果存在,看看是不是一个函数
                if (typeof this.msgList[msgName] === 'function') {
                    // 如果是,则变成数组
                    this.msgList[msgName] = [this.msgList[msgName], fn]
                } else {
                    this.msgList[msgName] = [...this.msgList[msgName], fn]
                }
            } else {
                // 如果消息名称在事件队列里不存在,直接存储
                this.msgList[msgName] = fn
            }
        }
        emit(msgName, msg) {
            // 先判断消息名称是否存在
            if (!this.msgList.hasOwnProperty(msgName)) {
                return
            }
            if (typeof this.msgList[msgName] === 'function') {
                // 函数的话直接执行
                this.msgList[msgName](msg)
            } else {
                this.msgList[msgName].map((fn) => {
                    fn(msg)
                })
            }
        }
        off(msgName) {
            if (!this.msgList.hasOwnProperty(msgName)) {
                return
            }
            delete this.msgList[msgName];
        }
    }

    // 调⽤参考 
    const bus = new EventBus();
    bus.on('event01', (eventArg) => console.log('event01', eventArg));
    bus.emit('event01', 123); //输出:event01 123

给你两个版本号 version1 和 version2比较

function compare( version1 ,  version2 ) {
    let arr1=version1.split(".");
    let arr2=version2.split(".");
    let length=Math.max(arr1.length,arr2.length);
    for (let i = 0; i < length; i++) {
        const n1 = Number(arr1[i]||0)
        const n2 = Number(arr2[i]||0)
        if (n1 > n2) return 1
        if (n1 < n2) return -1
    }
    return 0
}

js 数组对象根据对象中的指定属性去重

(1)方法一:循环判断

function unique(arr,u_key){
  let result = []
  result[0] = arr[0]
  arr.forEach((meta_item,i)=>{
    //声明计数变量,如果源数组中的一个对象和result结果数组中的所有对象不同,就push
    let num = 0
    result.forEach((r_item,j)=>{
      if (meta_item[u_key]!==r_item[u_key]) {
        num++
      }
      if (num === result.length) {
        result.push(meta_item)
      }
    })
  })
  return result
}


(2)方法二:利用对象属性唯一

function unique(arr, u_key) {
    const obj = {}
    const result = []
    arr.forEach(item => {
        const typeof_key = typeof item[u_key] + item[u_key]
        console.log(typeof_key);
        obj[typeof_key] = item
    })
    for (const key in obj) {
        result.push(obj[key])
    }
    return result
}

(3)方法三:利用ES6的Map方法

function unique(arr,u_key) {
      let map = new Map()
      arr.forEach((item,index)=>{
        if (!map.has(item[u_key])){
          map.set(item[u_key],item)
        }
      })
      return [...map.values()]
    }

(4)方法四:利用lodash库进行处理

如果项目中有引入lodash库的话,,就可以只用使用下面的uniqBy,传入对应的数组对象,和要根据的相关字段即可。

let unarrlist = this.$lodash.uniqBy(Arrlist,'insurerCode');
console.log(unarrlist)

let unArr = this.$lodash.uniqBy(arrayList,'id');
console.log(unArr)