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

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

⛲ Object篇


能不能写一个完整的深拷贝


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


const getType = obj => Object.prototype.toString.call(obj);
const isObject = (target) => (typeof target === 'object' || typeof target === 'function') && target !== null;
const canTraverse = {
  '[object Map]': true,
  '[object Set]': true,
  '[object Array]': true,
  '[object Object]': true,
  '[object Arguments]': true,
};
const mapTag = '[object Map]';
const setTag = '[object Set]';
const boolTag = '[object Boolean]';
const numberTag = '[object Number]';
const stringTag = '[object String]';
const symbolTag = '[object Symbol]';
const dateTag = '[object Date]';
const errorTag = '[object Error]';
const regexpTag = '[object RegExp]';
const funcTag = '[object Function]';
const handleRegExp = (target) => {
  const { source, flags } = target;
  return new target.constructor(source, flags);
}
const handleFunc = (func) => {
  // 箭头函数直接返回自身
  if(!func.prototype) return func;
  const bodyReg = /(?<={)(.|\n)+(?=})/m;
  const paramReg = /(?<=\().+(?=\)\s+{)/;
  const funcString = func.toString();
  // 分别匹配 函数参数 和 函数体
  const param = paramReg.exec(funcString);
  const body = bodyReg.exec(funcString);
  if(!body) return null;
  if (param) {
    const paramArr = param[0].split(',');
    return new Function(...paramArr, body[0]);
  } else {
    return new Function(body[0]);
  }
}
const handleNotTraverse = (target, tag) => {
  const Ctor = target.constructor;
  switch(tag) {
    case boolTag:
      return new Object(Boolean.prototype.valueOf.call(target));
    case numberTag:
      return new Object(Number.prototype.valueOf.call(target));
    case stringTag:
      return new Object(String.prototype.valueOf.call(target));
    case symbolTag:
      return new Object(Symbol.prototype.valueOf.call(target));
    case errorTag: 
    case dateTag:
      return new Ctor(target);
    case regexpTag:
      return handleRegExp(target);
    case funcTag:
      return handleFunc(target);
    default:
      return new Ctor(target);
  }
}
const deepClone = (target, map = new WeakMap()) => {
  if(!isObject(target)) 
    return target;
  let type = getType(target);
  let cloneTarget;
  if(!canTraverse[type]) {
    // 处理不能遍历的对象
    return handleNotTraverse(target, type);
  }else {
    // 这波操作相当关键,可以保证对象的原型不丢失!
    let ctor = target.constructor;
    cloneTarget = new ctor();
  }
  if(map.get(target)) 
    return target;
  map.set(target, true);
  if(type === mapTag) {
    //处理Map
    target.forEach((item, key) => {
      cloneTarget.set(deepClone(key, map), deepClone(item, map));
    })
  }
  if(type === setTag) {
    //处理Set
    target.forEach(item => {
      cloneTarget.add(deepClone(item, map));
    })
  }
  // 处理数组和对象
  for (let prop in target) {
    if (target.hasOwnProperty(prop)) {
        cloneTarget[prop] = deepClone(target[prop], map);
    }
  }
  return cloneTarget;
}
复制代码


参考博客


实现new


考察频率: (⭐⭐⭐⭐)


function createObject(Con) {
    // 创建新对象obj
    // var obj = {};也可以
    var obj = Object.create(null);
    // 将obj.__proto__ -> 构造函数原型
    // (不推荐)obj.__proto__ = Con.prototype
    Object.setPrototypeOf(obj, Con.prototype);
    // 执行构造函数,并接受构造函数返回值
    const ret = Con.apply(obj, [].slice.call(arguments, 1));
    // 若构造函数返回值为对象,直接返回该对象
    // 否则返回obj
    return typeof(ret) === 'object' ? ret: obj;
}
复制代码


继承


考察频率: (⭐⭐⭐⭐)


原型链继承


借用构造函数(经典继承)


组合继承


原型式继承


寄生式继承


寄生组合式继承


Class实现继承(补充一下)


class Animal {
    constructor(name) {
        this.name = name
    } 
    getName() {
        return this.name
    }
}
class Dog extends Animal {
    constructor(name, age) {
        super(name)
        this.age = age
    }
}
复制代码


参考代码


实现object.create


function newCreate(proto, propertiesObject) {
    if (typeof proto !== 'object' && typeof proto !== 'function') {
        throw TypeError('Object prototype may only be an Object: ' + proto)
    }
    function F() { }
    F.prototype = proto
    const o = new F()
    if (propertiesObject !== undefined) {
        Object.keys(propertiesObject).forEach(prop => {
            let desc = propertiesObject[prop]
            if (typeof desc !== 'object' || desc === null) {
                throw TypeError('Object prorotype may only be an Object: ' + desc)
            } else {
                Object.defineProperty(o, prop, desc)
            }
        })
    }
    return o
}
复制代码


🚂 Function篇


call


考察频率: (⭐⭐⭐⭐)


Function.prototype.myCall = function (thisArg) {
    thisArg = thisArg || window;
    thisArg.func = this;
    const args = []
    for (let i = 1; i<arguments.length; i++) {
        args.push('arguments['+ i + ']')
    }
    const result = eval('thisArg.func(' + args +')')
    delete thisArg.func;
    return result;
}
复制代码


bind


考察频率: (⭐⭐⭐⭐)


Function.prototype.sx_bind = function (obj, ...args) {
    obj = obj || window
    const fn = Symbol()
    obj[fn] = this
    const _this = this
    const res = function (...innerArgs) {
        console.log(this, _this)
        if (this instanceof _this) {
            this[fn] = _this
            this[fn](...[...args, ...innerArgs])
            delete this[fn]
        } else {
            obj[fn](...[...args, ...innerArgs])
            delete obj[fn]
        }
    }
    res.prototype = Object.create(this.prototype)
    return res
}
复制代码


apply


考察频率: (⭐⭐⭐⭐)


Function.prototype.myApply = function (thisArg, arr) {
    thisArg = thisArg || window;
    thisArg.func = this;
    const args = []
    for (let i = 0; i<arr.length; i++) {
        args.push('arr['+ i + ']')
    }
    const result = eval('thisArg.func(' + args +')')
    delete thisArg.func;
    return result;
}
复制代码


实现柯里化


考察频率: (⭐⭐⭐)


参考代码


实现链式调用


参考代码


偏函数


参考代码


🌍 ajax 与 jsonp


考察频率: (⭐⭐⭐)


实现ajax


function ajax({
    url= null,
  method = 'GET',
  dataType = 'JSON',
  async = true}){
  return new Promise((resolve, reject) => {
    let xhr = new XMLHttpRequest()
    xhr.open(method, url, async)
    xhr.responseType = dataType
    xhr.onreadystatechange = () => {
      if(!/^[23]\d{2}$/.test(xhr.status)) return;
      if(xhr.readyState === 4) {
        let result = xhr.responseText
        resolve(result)
      }
    }
    xhr.onerror = (err) => {
      reject(err)
    }
    xhr.send()
  })
}
复制代码


实现jsonp


const jsonp = ({ url, params, callbackName }) => {
    const generateUrl = () => {
        let dataSrc = ''
        for (let key in params) {
            if (params.hasOwnProperty(key)) {
                dataSrc += `${key}=${params[key]}&`
            }
        }
        dataSrc += `callback=${callbackName}`
        return `${url}?${dataSrc}`
    }
    return new Promise((resolve, reject) => {
        const scriptEle = document.createElement('script')
        scriptEle.src = generateUrl()
        document.body.appendChild(scriptEle)
        window[callbackName] = data => {
            resolve(data)
            document.removeChild(scriptEle)
        }
    })
}
复制代码


🛫 ES6篇


实现set


class Set {
  constructor() {
    this.items = {};
    this.size = 0;
  }
  has(element) {
    return element in this.items;
  }
  add(element) {
    if(! this.has(element)) {
      this.items[element] = element;
      this.size++;
    }
    return this;
  }
  delete(element) {
    if (this.has(element)) {
      delete this.items[element];
      this.size--;
    }
    return this;
  }
  clear() {
    this.items = {}
    this.size = 0;
  }
  values() {
    let values = [];
    for(let key in this.items) {
      if(this.items.hasOwnProperty(key)) {
        values.push(key);
      }
    }
    return values;
  }
}
复制代码


实现 map


function defaultToString(key) {
  if(key === null) {
    return 'NULL';
  } else if (key === undefined) {
    return 'UNDEFINED'
  } else if (Object.prototype.toString.call(key) === '[object Object]' || Object.prototype.toString.call(key) === '[object Array]') {
    return JSON.stringify(key);
  }
  return key.toString();
}
class Map {
  constructor() {
    this.items = {};
    this.size = 0;
  }
  set(key, value) {
    if(!this.has(key)) {
      this.items[defaultToString(key)] = value;
      this.size++;
    }
    return this;
  }
  get(key) {
    return this.items[defaultToString(key)];
  }
  has(key) {
    return this.items[defaultToString(key)] !== undefined;
  }
  delete(key) {
    if (this.has(key)) {
      delete this.items[key];
      this.size--;
    }
    return this;
  }
  clear() {
    this.items = {}
    this.size = 0;
  }
  keys() {
    let keys = [];
    for(let key in this.items) {
      if(this.has(key)) {
        keys.push(key)
      }
    }
    return keys;
  }
  values() {
    let values = [];
    for(let key in this.items) {
      if(this.has(key)) {
        values.push(this.items[key]);
      }
    }
    return values;
  }
}
复制代码


实现es6的class


参考代码


🦉 其他


instanceof


考察频率: (⭐⭐⭐⭐)


function instance_of(Case, Constructor) {
    // 基本数据类型返回false
    // 兼容一下函数对象
    if ((typeof(Case) != 'object' && typeof(Case) != 'function') || Case == 'null') return false;
    let CaseProto = Object.getPrototypeOf(Case);
    while (true) {
        // 查到原型链顶端,仍未查到,返回false
        if (CaseProto == null) return false;
        // 找到相同的原型
        if (CaseProto === Constructor.prototype) return true;
        CaseProto = Object.getPrototypeOf(CaseProto);
    }
}
复制代码


实现千分位分隔符


考察频率: (⭐⭐⭐)


var str = "100000000000",
    reg = /(?=(\B\d{3})+$)/g;
str.replace(reg, ",")
复制代码


把一个JSON对象的key从下划线形式(Pascal)转换到小驼峰形式(Camel)


考察频率: (⭐⭐⭐)


参考代码


实现数据类型判断函数


function myTypeof(obj) {
   return Object.prototype.toString.call(obj).slice(8, -1).toLowerCase() 
}
复制代码


实现数组转树


参考代码


实现sleep函数


// promise
const sleep = time => {
  return new Promise(resolve => setTimeout(resolve,time))
}
sleep(1000).then(()=>{
  console.log(1)
})
// ES5
function sleep(callback,time) {
  if(typeof callback === 'function')
    setTimeout(callback,time)
}
function output(){
  console.log(1);
}
sleep(output,1000);
复制代码


实现发布订阅模式


class EventEmitter {
    constructor() {
        this.cache = {}
    }
    on(name, fn) {
        if (this.cache[name]) {
            this.cache[name].push(fn)
        } else {
            this.cache[name] = [fn]
        }
    }
    off(name, fn) {
        let tasks = this.cache[name]
        if (tasks) {
            const index = tasks.findIndex(f => f === fn || f.callback === fn)
            if (index >= 0) {
                tasks.splice(index, 1)
            }
        }
    }
    emit(name, once = false, ...args) {
        if (this.cache[name]) {
            // 创建副本,如果回调函数内继续注册相同事件,会造成死循环
            let tasks = this.cache[name].slice()
            for (let fn of tasks) {
                fn(...args)
            }
            if (once) {
                delete this.cache[name]
            }
        }
    }
}
复制代码


🛕 更多题目


传送门: 前端题目

如果感觉有帮助的话,别忘了给小包点个 ⭐ 。

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