关于前端面试要求手写的功能函数

前端小伙伴们在面试中经常会遇到面试的时候让手写一些函数,那么下面我讲整理一些面试中可能遇到的手写函数,供大家参考。

一、防抖

function debounce(fn, wait) {
    
    
  let timer
  return function (...e) {
    
    
    if (timer) {
    
    
      clearTimeout(timer)
    }
    timer = setTimeout(() => {
    
    
      fn.apply(this, e)
    }, wait)
  }
}

// 测试
function test() {
    
    
  console.log('run scroll')
}
const debounceTest = debounce(test, 1000)
window.addEventListener('scroll', debounceTest)

二、节流

function throttle(fn, time) {
    
    
  let last = 0 // 上次触发时间
  return (...e) => {
    
    
    const now = Date.now()
    if (now - last > time) {
    
    
      last = now
      fn.apply(this, e)
    }
  }
}

// 测试
function test() {
    
    
  console.log('run scroll')
}
const throttleTest = throttle(test, 1000)
window.addEventListener('scroll', throttleTest)

三、深拷贝

function deepClone(obj, cache = new WeakMap()) {
    
    
  if (obj === null || typeof obj !== 'object') return obj
  if (obj instanceof Date) return new Date(obj)
  if (obj instanceof RegExp) return new RegExp(obj)
  
  if (cache.get(obj)) return cache.get(obj) // 如果出现循环引用,则返回缓存的对象,防止递归进入死循环
  let cloneObj = new obj.constructor() // 使用对象所属的构造函数创建一个新对象
  cache.set(obj, cloneObj) // 缓存对象,用于循环引用的情况

  for (let key in obj) {
    
    
    if (obj.hasOwnProperty(key)) {
    
    
      cloneObj[key] = deepClone(obj[key], cache) // 递归拷贝
    }
  }
  return cloneObj
}

// 测试
const obj = {
    
     name: 'Jack', address: {
    
     x: 100, y: 200 } }
obj.a = obj // 循环引用
const newObj = deepClone(obj)
console.log(newObj.address === obj.address) // false

在项目中一般只需要用到JSON序列化或者解构就可以满足。

JSON..parse(JSON.stringify(obj))
[...arr]
{
    
    ...obj}

JSON序列化只会处理简单属性和简单属性数组,如果需要拷贝比较复杂的数组或对象请用第一个方法。

四、手写Promise

class MyPromise {
    
    
  constructor(executor) {
    
    
    this.status = 'pending' // 初始状态为等待
    this.value = null // 成功的值
    this.reason = null // 失败的原因
    this.onFulfilledCallbacks = [] // 成功的回调函数存放的数组
    this.onRejectedCallbacks = [] // 失败的回调函数存放的数组
    let resolve = value => {
    
    
      if (this.status === 'pending') {
    
    
        this.status = 'fulfilled'
        this.value = value;
        this.onFulfilledCallbacks.forEach(fn => fn()) // 调用成功的回调函数
      }
    }
    let reject = reason => {
    
    
      if (this.status === 'pending') {
    
    
        this.status = 'rejected'
        this.reason = reason
        this.onRejectedCallbacks.forEach(fn => fn()) // 调用失败的回调函数
      }
    };
    try {
    
    
      executor(resolve, reject)
    } catch (err) {
    
    
      reject(err)
    }
  }
  then(onFulfilled, onRejected) {
    
    
    // onFulfilled如果不是函数,则修改为函数,直接返回value
    onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value
    // onRejected如果不是函数,则修改为函数,直接抛出错误
    onRejected = typeof onRejected === 'function' ? onRejected : err => {
    
     throw err }
    return new MyPromise((resolve, reject) => {
    
    
      if (this.status === 'fulfilled') {
    
    
        setTimeout(() => {
    
    
          try {
    
    
            let x = onFulfilled(this.value);
            x instanceof MyPromise ? x.then(resolve, reject) : resolve(x)
          } catch (err) {
    
    
            reject(err)
          }
        })
      }
      if (this.status === 'rejected') {
    
    
        setTimeout(() => {
    
    
          try {
    
    
            let x = onRejected(this.reason)
            x instanceof MyPromise ? x.then(resolve, reject) : resolve(x)
          } catch (err) {
    
    
            reject(err)
          }
        })
      }
      if (this.status === 'pending') {
    
    
        this.onFulfilledCallbacks.push(() => {
    
     // 将成功的回调函数放入成功数组
          setTimeout(() => {
    
    
            let x = onFulfilled(this.value)
            x instanceof MyPromise ? x.then(resolve, reject) : resolve(x)
          })
        })
        this.onRejectedCallbacks.push(() => {
    
     // 将失败的回调函数放入失败数组
          setTimeout(() => {
    
    
            let x = onRejected(this.reason)
            x instanceof MyPromise ? x.then(resolve, reject) : resolve(x)
          })
        })
      }
    })
  }
}

// 测试
function p1() {
    
    
  return new MyPromise((resolve, reject) => {
    
    
    setTimeout(resolve, 1000, 1)
  })
}
function p2() {
    
    
  return new MyPromise((resolve, reject) => {
    
    
    setTimeout(resolve, 1000, 2)
  })
}
p1().then(res => {
    
    
  console.log(res) // 1
  return p2()
}).then(ret => {
    
    
  console.log(ret) // 2
})

五、异步处理并发数量

function limitRequest(urls = [], limit = 3) {
    
    
  return new Promise((resolve, reject) => {
    
    
    const len = urls.length
    let count = 0

    // 同时启动limit个任务
    while (limit > 0) {
    
    
      start()
      limit -= 1
    }

    function start() {
    
    
      const url = urls.shift() // 从数组中拿取第一个任务
      if (url) {
    
    
        axios.post(url).then(res => {
    
    
          // todo
        }).catch(err => {
    
    
          // todo
        }).finally(() => {
    
    
          if (count == len - 1) {
    
    
            // 最后一个任务完成
            resolve()
          } else {
    
    
            // 完成之后,启动下一个任务
            count++
            start()
          }
        })
      }
    }

  })
}

// 测试
limitRequest(['https://aaa', 'https://bbb', 'https://ccc', 'https://ddd', 'https://eee'])

六、继承

ES5继承

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

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

// 测试
let xm = new Child('啦啦啦', 12) 
console.log(xm.name) // 啦啦啦
console.log(xm.age) // 12
xm.eat() // 啦啦啦 巴拉巴拉

ES6继承

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

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

// 测试
let xm = new Child('啦啦啦', 12) 
console.log(xm.name) // 啦啦啦
console.log(xm.age) // 12
xm.eat() // 啦啦啦 巴拉巴拉

七、数组排序

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 swap(arr, indexA, indexB) {
    
    
  var temp;
  temp = arr[indexA];
  arr[indexA] = arr[indexB];
  arr[indexB] = temp;
}
function bubbleSort(arr, compareFunc) {
    
    
  for (let i = arr.length - 1; i > 0; i--) {
    
    
    for (let j = 0; j < i; j++) {
    
    
      if (compareFunc(arr[j], arr[j + 1]) > 0) {
    
    
        swap(arr, j, j + 1);
      }
    }
  }
  return arr;
}
var arr = [91, 60, 96, 7, 35, 65, 10, 65, 9, 30, 20, 31, 77, 81, 24];
console.log(bubbleSort(arr, (a, b) => a - b));
console.log(bubbleSort(arr, (a, b) => b - a));

数组内对象按时间排序算法

var jsonArr = [
  {
    
    date : "2017-8-3 13:50:56" , key:"XX"},
  {
    
    date : "2017-8-2 11:50:56" , key:"XX"},
  {
    
    date : "2017-7-5 13:52:56" , key:"XX"},
  {
    
    date : "2017-11-3 13:50:56" , key:"XX"},
  {
    
    date : "2017-2-3 12:50:56" , key:"XX"},
  {
    
    date : "2017-8-3 14:58:56" , key:"XX"}
];
 
//排序
jsonArr.sort(function(a,b){
    
    
   if(typeof(a) == "object" && typeof(b) == "object"){
    
    
       return new Date (a['date']).getTime() > new Date (b['date']).getTime() ? 1 : -1;  //正序 
       //return new Date (a['date']).getTime() > new Date (b['date']).getTime() ? -1 : 1;  //倒叙 , 
 
   }
});
console.log(jsonArr);

八、数组去重

ES6 Set 去重

const newArr = [...new Set(arr)]
// 或
const newArr = Array.from(new Set(arr))

indexOf 去重

function resetArr(arr) {
    
    
  let res = []
  arr.forEach(item => {
    
    
    if (res.indexOf(item) === -1) {
    
    
      res.push(item)
    }
  })
  return res
}

// 测试
const arr = [1, 1, 2, 3, 3]
console.log(resetArr(arr)) // [1, 2, 3]

数组内对象去重

let person = [
     {
    
    id: 0, name: "小明"},
     {
    
    id: 1, name: "小张"},
     {
    
    id: 2, name: "小李"},
     {
    
    id: 3, name: "小孙"},
     {
    
    id: 1, name: "小周"},
     {
    
    id: 2, name: "小陈"},   
];
 
let obj = {
    
    };
 
let peon = person.reduce((cur,next,index,arr) => {
    
    
    console.log(cur,next,index,arr)
    obj[next.id] ? "" : obj[next.id] = true && cur.push(next);
    return cur;
},[]) //设置cur默认类型为数组,并且初始值为空的数组
console.log(peon);

九、获取Url参数

URLSearchParams 方法

// 创建一个URLSearchParams实例
const urlSearchParams = new URLSearchParams(window.location.search);
// 把键值对列表转换为一个对象
const params = Object.fromEntries(urlSearchParams.entries());

split 方法

function getParams(url) {
    
    
  const res = {
    
    }
  if (url.includes('?')) {
    
    
    const str = url.split('?')[1]
    const arr = str.split('&')
    arr.forEach(item => {
    
    
      const key = item.split('=')[0]
      const val = item.split('=')[1]
      res[key] = decodeURIComponent(val) // 解码
    })
  }
  return res
}

// 测试
const user = getParams('http://www.baidu.com?user=%E9%98%BF%E9%A3%9E&age=16')
console.log(user) // { user: '阿飞', age: '16' }

十、递归的方式写1到100求和

function add(num1,num2){
    
    
	var num = num1+num2;
        if(num2+1>100){
    
    
	 return num;
	}else{
    
    
	  return add(num,num2+1)
        }
 }
var sum =add(1,2); 
console.log(sum) // 5050

十一、闭包

function makeFunc() {
    
    
    var name = "Mozilla"
    function displayName() {
    
    
        console.log(name)
    }
    return displayName
}

var myFunc = makeFunc() 
myFunc()

猜你喜欢

转载自blog.csdn.net/Jensen_Yao/article/details/123394238
今日推荐