2021年前端各大公司都考了那些手写题(附带代码)(一)

简介: 2021年前端各大公司都考了那些手写题(附带代码)(一)

🎄 前言



本文主要总结了 2021 年前端提前批和秋招所考察的手写题,题目来源于牛客网前端面经区,统计时间自 3 月初至 10 月底,面经来源于阿里、腾讯、百度、字节、美团、京东、快手、拼多多等 15 家公司,并做了简单的频次划分。


  • ⭐⭐⭐⭐⭐: 在 15 家公司面试中出现 10+
  • ⭐⭐⭐⭐:在 15 家公式面试中出现 5-10
  • ⭐⭐⭐:在 15 家公司面试中出现 3-5
  • 无星:出现 1-2


题目解析一部分来源于小包的编写,另一部分如果我感觉题目扩展开来更好的话,我就选取部分大佬的博客链接。


🌟 promise


实现promise


考察频率: (⭐⭐⭐⭐⭐)


参考代码


实现promise.all


考察频率: (⭐⭐⭐⭐⭐)


function PromiseAll(promises){
    return new Promise((resolve, reject)=>{
        if(!Array.isArray(promises)){
            throw new TypeError("promises must be an array")
        }
        let result = [] 
        let count = 0 
        promises.forEach((promise, index) => {
            promise.then((res)=>{
                result[index] = res
                count++
                count === promises.length && resolve(result) 
            }, (err)=>{
                reject(err)
            })
        })
    })
}
复制代码


实现 promise.finally


考察频率: (⭐⭐⭐⭐⭐)


Promise.prototype.finally = function (cb) {
  return this.then(function (value) {
    return Promise.resolve(cb()).then(function () {
      return value
    })
  }, function (err) {
    return Promise.resolve(cb()).then(function () {
      throw err
    })
  })
}
复制代码


实现promise.allSettled


考察频率: (⭐⭐⭐⭐)


function allSettled(promises) {
  if (promises.length === 0) return Promise.resolve([])
  const _promises = promises.map(
    item => item instanceof Promise ? item : Promise.resolve(item)
    )
  return new Promise((resolve, reject) => {
    const result = []
    let unSettledPromiseCount = _promises.length
    _promises.forEach((promise, index) => {
      promise.then((value) => {
        result[index] = {
          status: 'fulfilled',
          value
        }
        unSettledPromiseCount -= 1
        // resolve after all are settled
        if (unSettledPromiseCount === 0) {
          resolve(result)
        }
      }, (reason) => {
        result[index] = {
          status: 'rejected',
          reason
        }
        unSettledPromiseCount -= 1
        // resolve after all are settled
        if (unSettledPromiseCount === 0) {
          resolve(result)
        }
      })
    })
  })
}
复制代码


实现promise.race


考察频率: (⭐⭐⭐)


Promise.race = function(promiseArr) {
    return new Promise((resolve, reject) => {
        promiseArr.forEach(p => {
            Promise.resolve(p).then(val => {
                resolve(val)
            }, err => {
                rejecte(err)
            })
        })
    })
}
复制代码


来说一下如何串行执行多个Promise


参考代码


promise.any


Promise.any = function(promiseArr) {
    let index = 0
    return new Promise((resolve, reject) => {
        if (promiseArr.length === 0) return 
        promiseArr.forEach((p, i) => {
            Promise.resolve(p).then(val => {
                resolve(val)
            }, err => {
                index++
                if (index === promiseArr.length) {
                  reject(new AggregateError('All promises were rejected'))
                }
            })
        })
    })
}
复制代码


resolve


Promise.resolve = function(value) {
    if(value instanceof Promise){
        return value
    }
    return new Promise(resolve => resolve(value))
}
复制代码


reject


Promise.reject = function(reason) {
    return new Promise((resolve, reject) => reject(reason))
}
复制代码


🐳 Array篇


数组去重


考察频率: (⭐⭐⭐⭐⭐)


使用双重 forsplice


function unique(arr){            
    for(var i=0; i<arr.length; i++){
        for(var j=i+1; j<arr.length; j++){
            if(arr[i]==arr[j]){         
            //第一个等同于第二个,splice方法删除第二个
                arr.splice(j,1);
                // 删除后注意回调j
                j--;
            }
        }
    }
return arr;
}
复制代码


使用 indexOfincludes 加新数组


//使用indexof
function unique(arr) {
    var uniqueArr = []; // 新数组
    for (let i = 0; i < arr.length; i++) {
        if (uniqueArr.indexOf(arr[i]) === -1) {
            //indexof返回-1表示在新数组中不存在该元素
            uniqueArr.push(arr[i])//是新数组里没有的元素就push入
        }
    }
    return uniqueArr;
}
// 使用includes
function unique(arr) {
    var uniqueArr = []; 
    for (let i = 0; i < arr.length; i++) {
        //includes 检测数组是否有某个值
        if (!uniqueArr.includes(arr[i])) {
            uniqueArr.push(arr[i])//
        }
    }
    return uniqueArr;
}
复制代码


sort 排序后,使用快慢指针的思想


function unique(arr) {
    arr.sort((a, b) => a - b);
    var slow = 1,
        fast = 1;
    while (fast < arr.length) {
        if (arr[fast] != arr[fast - 1]) {
            arr[slow ++] = arr[fast];
        }
        ++ fast;
    }
    arr.length = slow;
    return arr;
}
复制代码


sort 方法用于从小到大排序(返回一个新数组),其参数中不带以上回调函数就会在两位数及以上时出现排序错误(如果省略,元素按照转换为的字符串的各个字符的 Unicode 位点进行排序。两位数会变为长度为二的字符串来计算)。


ES6 提供的 Set 去重


function unique(arr) {
    const result = new Set(arr);
    return [...result];
    //使用扩展运算符将Set数据结构转为数组
}
复制代码


Set 中的元素只会出现一次,即 Set 中的元素是唯一的。


使用哈希表存储元素是否出现(ES6 提供的 map)


function unique(arr) {
    let map = new Map();
    let uniqueArr = new Array();  // 数组用于返回结果
    for (let i = 0; i < arr.length; i++) {
      if(map.has(arr[i])) {  // 如果有该key值
        map.set(arr[i], true); 
      } else { 
        map.set(arr[i], false);   // 如果没有该key值
        uniqueArr.push(arr[i]);
      }
    } 
    return uniqueArr ;
}
复制代码


map 对象保存键值对,与对象类似。但 map 的键可以是任意类型,对象的键只能是字符串类型。


如果数组中只有数字也可以使用普通对象作为哈希表。


filter 配合 indexOf


function unique(arr) {
    return arr.filter(function (item, index, arr) {
        //当前元素,在原始数组中的第一个索引==当前索引值,否则返回当前元素
        //不是那么就证明是重复项,就舍弃
        return arr.indexOf(item) === index;
    })
}
复制代码


这里有可能存在疑问,我来举个例子:


const arr = [1,1,2,1,3]
arr.indexOf(arr[0]) === 0 // 1 的第一次出现
arr.indexOf(arr[1]) !== 1 // 说明前面曾经出现过1
复制代码


reduce 配合 includes


function unique(arr){
    let uniqueArr = arr.reduce((acc,cur)=>{
        if(!acc.includes(cur)){
            acc.push(cur);
        }
        return acc;
    },[]) // []作为回调函数的第一个参数的初始值
    return uniqueArr
}
复制代码


数组扁平化


考察频率: (⭐⭐⭐)


参考代码


forEach


考察频率: (⭐⭐⭐)


Array.prototype.myForEach = function (callbackFn) {
    // 判断this是否合法
    if (this === null || this === undefined) {
        throw new TypeError("Cannot read property 'myForEach' of null");
    }
    // 判断callbackFn是否合法
    if (Object.prototype.toString.call(callbackFn) !== "[object Function]") {
        throw new TypeError(callbackFn + ' is not a function')
    }
    // 取到执行方法的数组对象和传入的this对象
    var _arr = this, thisArg = arguments[1] || window;
    for (var i = 0; i < _arr.length; i++) {
        // 执行回调函数
        callbackFn.call(thisArg, _arr[i], i, _arr);
    }
}
复制代码


reduce


考察频率: (⭐⭐⭐)


Array.prototype.myReduce = function(callbackFn) {
    var _arr = this, accumulator = arguments[1];
    var i = 0;
    // 判断是否传入初始值
    if (accumulator === undefined) {
        // 没有初始值的空数组调用reduce会报错
        if (_arr.length === 0) {
            throw new Error('initVal and Array.length>0 need one')
        }
        // 初始值赋值为数组第一个元素
        accumulator = _arr[i];
        i++;
    }
    for (; i<_arr.length; i++) {
        // 计算结果赋值给初始值
        accumulator = callbackFn(accumulator,  _arr[i], i, _arr)
    }
    return accumulator;
}
复制代码


map


Array.prototype.myMap = function(callbackFn) {
    var _arr = this, thisArg = arguments[1] || window, res = [];
    for (var i = 0; i<_arr.length; i++) {
        // 存储运算结果
        res.push(callbackFn.call(thisArg, _arr[i], i, _arr));
    }
    return res;
}
复制代码


filter


Array.prototype.myFilter = function(callbackFn) {
    var _arr = this, thisArg = arguments[1] || window, res = [];
    for (var i = 0; i<_arr.length; i++) {
        // 回调函数执行为true
        if (callbackFn.call(thisArg, _arr[i], i, _arr)) {
            res.push(_arr[i]);
        }
    }
    return res;
}
复制代码


every


Array.prototype.myEvery = function(callbackFn) {
    var _arr = this, thisArg = arguments[1] || window;
    // 开始标识值为true
    // 遇到回调返回false,直接返回false
    // 如果循环执行完毕,意味着所有回调返回值为true,最终结果为true
    var flag = true;
    for (var i = 0; i<_arr.length; i++) {
        // 回调函数执行为false,函数中断
        if (!callbackFn.call(thisArg, _arr[i], i, _arr)) {
            return false;
        }
    }
    return flag;
}
复制代码


some


Array.prototype.mySome = function(callbackFn) {
    var _arr = this, thisArg = arguments[1] || window;
    // 开始标识值为false
    // 遇到回调返回true,直接返回true
    // 如果循环执行完毕,意味着所有回调返回值为false,最终结果为false
    var flag = false;
    for (var i = 0; i<_arr.length; i++) {
        // 回调函数执行为false,函数中断
        if (callbackFn.call(thisArg, _arr[i], i, _arr)) {
            return true;
        }
    }
    return flag;
}
复制代码


find/findIndex


Array.prototype.myFind = function(callbackFn) {
    var _arr = this, thisArg = arguments[1] || window;
    // 遇到回调返回true,直接返回该数组元素
    // 如果循环执行完毕,意味着所有回调返回值为false,最终结果为undefined
    for (var i = 0; i<_arr.length; i++) {
        // 回调函数执行为false,函数中断
        if (callbackFn.call(thisArg, _arr[i], i, _arr)) {
            return _arr[i];
        }
    }
    return undefined;
}
复制代码


indexOf


function indexOf(findVal, beginIndex = 0) {
    if (this.length < 1 || beginIndex > findVal.length) {
        return -1;
    }
    if (!findVal) {
        return 0;
    }
    beginIndex = beginIndex <= 0 ? 0 : beginIndex;
    for (let i = beginIndex; i < this.length; i++) {
        if (this[i] == findVal) return i;
    }
    return -1;
}
复制代码


实现sort


参考代码


🌊 防抖节流


实现防抖函数debounce


考察频率: (⭐⭐⭐⭐⭐)


function debounce(func, wait, immediate) {
    var timeout, result;
    var debounced = function () {
        var context = this;
        var args = arguments;
        if (timeout) clearTimeout(timeout);
        if (immediate) {
            // 如果已经执行过,不再执行
            var callNow = !timeout;
            timeout = setTimeout(function(){
                timeout = null;
            }, wait)
            if (callNow) result = func.apply(context, args)
        }
        else {
            timeout = setTimeout(function(){
                result = func.apply(context, args)
            }, wait);
        }
        return result;
    };
    debounced.cancel = function() {
        clearTimeout(timeout);
        timeout = null;
    };
    return debounced;
}
复制代码


实现节流函数throttle


考察频率: (⭐⭐⭐⭐⭐)


// 第四版
function throttle(func, wait, options) {
    var timeout, context, args, result;
    var previous = 0;
    if (!options) options = {};
    var later = function() {
        previous = options.leading === false ? 0 : new Date().getTime();
        timeout = null;
        func.apply(context, args);
        if (!timeout) context = args = null;
    };
    var throttled = function() {
        var now = new Date().getTime();
        if (!previous && options.leading === false) previous = now;
        var remaining = wait - (now - previous);
        context = this;
        args = arguments;
        if (remaining <= 0 || remaining > wait) {
            if (timeout) {
                clearTimeout(timeout);
                timeout = null;
            }
            previous = now;
            func.apply(context, args);
            if (!timeout) context = args = null;
        } else if (!timeout && options.trailing !== false) {
            timeout = setTimeout(later, remaining);
        }
    };
    return throttled;
}
复制代码


相关文章
|
18天前
|
前端开发 小程序 Java
uniapp上传图片 前端以及java后端代码实现
uniapp上传图片 前端以及java后端代码实现
32 0
|
21天前
|
缓存 前端开发
前端代码整洁与规范之CSS篇
【4月更文挑战第2天】 前端代码整洁与规范之CSS篇
41 4
|
1月前
|
JSON 前端开发 Java
layui上传图片,前端直接拷代码,后端……
layui上传图片,前端直接拷代码,后端……
29 0
|
1月前
|
缓存 前端开发 JavaScript
揭秘前端性能优化:从代码到用户体验的全面升级
揭秘前端性能优化:从代码到用户体验的全面升级
20 0
|
10天前
|
前端开发 JavaScript 算法
比较流行的前端代码书写规范都有哪些
【4月更文挑战第13天】前端代码规范增进代码可读性和团队协作,包括缩进(用2空格)、命名(变量 camelCase,常量 MY_CONSTANT,类 PascalCase)、注释、语句与表达式、错误处理、代码复用。文件命名规范涉及扩展名、目录结构、简洁文件名、入口文件和配置文件命名。遵循这些规范能提高代码一致性,但需按项目需求调整。不断学习新规范以适应前端技术发展。
14 1
|
12天前
|
监控 前端开发 JavaScript
如何使用浏览器调试前端代码?
【4月更文挑战第11天】前端开发中,浏览器调试是关键技能,能提升代码质量。本文介绍了如何使用浏览器的调试工具:1) 打开调试窗口(F12或右键检查);2) Elements标签页检查DOM结构和样式;3) Console调试JavaScript,查看日志和错误信息;4) Sources设置断点调试JS文件;5) 利用Network、Performance和Memory等标签页优化性能。熟悉调试工具、利用日志和错误信息能有效定位问题,提高开发效率。
33 7
|
1月前
|
前端开发 开发者
React Hooks:提升前端开发效率和代码可维护性
传统的 React 类组件在处理状态管理和生命周期函数时存在一些限制,而引入的 React Hooks 技术可以帮助前端开发者更高效地管理组件状态和逻辑,提升代码的可读性和可维护性。本文将介绍 React Hooks 的基本用法及其在实际项目中的应用场景。
|
8月前
|
Web App开发 前端开发 JavaScript
前端学习笔记202307学习笔记第五十七天-模拟面试笔记react-fiber解决了什么问题
前端学习笔记202307学习笔记第五十七天-模拟面试笔记react-fiber解决了什么问题
95 0
|
8月前
|
前端开发 定位技术
前端学习笔记202305学习笔记第二十三天-地图单线程配置
前端学习笔记202305学习笔记第二十三天-地图单线程配置
64 0
前端学习笔记202305学习笔记第二十三天-地图单线程配置
|
8月前
|
前端开发 API
前端学习笔记202307学习笔记第五十七天-模拟面试笔记react-react-redux的工作流程
前端学习笔记202307学习笔记第五十七天-模拟面试笔记react-react-redux的工作流程
55 0