# 一面

  1. leetcode第112题, 路径总和
const hasPathSum = (root, sum) => {
  if (root === null) { // 遍历到null节点
    return false;
  }
  if (root.left === null && root.right === null) { // 遍历到叶子节点
    return sum - root.val === 0; // 如果满足这个就返回true,否则返回false
  }
  //不是上面情况,则拆成两个子树的问题,其中一个true就行
  return hasPathSum(root.left, sum - root.val) || hasPathSum(root.right, sum - root.val)
}
  1. 你知道的数组API
方法 作用 是否影响原数组
push 在数组后添加元素,返回长度 ✅
pop 删除数组最后一项,返回被删除项 ✅
shift 删除数组第一项,返回删除项 ✅
unshift 数组开头添加元素,返回长度 ✅
reverse 反转数组,返回数组 ✅
sort 排序数组,返回数组 ✅
splice 截取数组,返回被截取的部分 ✅
join 将数组转为字符串,返回字符 ❌
concat 连接数组 ❌
map 相同规则处理数组项,返回新数组 ❌
forEach 遍历数组 ❌
filter 过滤数组项,返回符合条件的数组 ❌
every 每一项符合规则才返回true ❌
some 只要一项符合规则才返回true ❌
reduce 接受上一个return和数组下一项 ❌
flat 数组扁平化 ❌
slice 截取数组,返回被截取区间 ❌
  1. 实现reduce
Array.prototype.reduce = Array.prototype.reduce || function(fn, initialValue) {
  let arr = this;
  let base = typeof initialValue === 'undefined' ? arr[0] : initialValue;
  let startPoint = typeof initialValue === 'undefined' ? 1 : 0;
  arr.slice(startPoint).forEach((val, index) => {
    base = fn(base, val, index + startPoint, arr);
  })
  retrun base;
}

// 第二种实现
Array.prototype.sx_reduce = function(callback, ...args) {
  let start = 0, base;
  if (args.length) {
    base = args[0]
  } else {
    base = this[0];
    start = 1;
  }
  this.slice(start).forEach((val, index) => {
    base = fn(base, val, index + startPoint, this);
  })
  retrun base;
}
  1. 将一下HTTP缓存

HTTP缓存

  1. vue与react区别和优劣
  • vue2 对ts支持较差,vue3已解决
  • vue2对jsx支持较差,vue3已解决
  • vue和react都是单向数据流
  • vue多用模板templeate react多用jsx
  • vue和react都用虚拟dom和diff算法
  • vue是双向绑定,react是单向绑定
  • vue和react都倡导组件化开发
  • vue和react都支持服务端渲染
  • vue2的状态管理工具是vuex,vue3用pinia,react用redux、mbox、recoil
  • vue的diff算法比react更高效
  • react的写法更贴近js原生
  1. hooks、react中class组件和函数组件的区别
  • class组件:state和props都是固定地址
  • 函数组件:state和props每次都随着渲染更新而更新
  1. 前端性能优化
  • 列表优化:懒加载,虚拟列表,分页
  • 重绘重排:合并修改、requestAnimationFrame、will-change
  • 提交优化:防抖
  • 网络优化:控制并发,取消重复请求,合并请求,http缓存
  • webpack优化:代码压缩,gzip,CND,代码分割,合理设置hash,图片转base64

# 二面

  1. 算法
fn([['a', 'b'], ['n', 'm'], ['0', '1']]) 
=> ['an0', 'am0', 'an1', 'am1', 'bn0', 'bm0', 'bn1', 'bm0']

解答:

const fn = arr => {
  const length = arr.length;
  const res = [];
  const dfs = (items, str = '', index = 1) => {
    if (index > length) {
      res.push(str);
    } else {
      for (const item of items) {
        dfs(arr[index], str + item, index + 1);
      }
    }
  }
  dfs(arr[0]);
  return res;
}

电话号码的字母组合 (opens new window)

  1. 手写
u.console('breakfast').setTimeout(3000)
.console('lunch').setTimeout(3000)
.console('dinner')

解答,参考

clas U {
  constructor() {
    this.tasks = [];
    setTimeout(() => {
      this.next();
    })
  }
  next() {
    const task = this.tasks.shift();
    task && task();
  }
  console(str) {
    const task = () => {
      console.log(str);
      this.next();
    }
    this.tasks.push(task);
    return this;
  }
  setTimeout(delay) {
    const task = () => {
      setTimeout(() => {
        this.next();
      }, delay)
    }
    this.tasks.push(task);
    return this;
  }
}
  1. 事件代理是什么

当子元素都需要绑定相同的事件的时候,这个时候可以把事件直接绑定在父元素上,并通过target对象来判断执行不同的子元素操作,这样可以大大减少绑定事件,减少DOM操作,提高性能

  1. e.target和e.currentTarget的区别
  • e.target:触发事件的元素
  • e.currentTarget:事件所绑定的元素
  1. 写一个事件代理函数,需要判断child是parent的子节点
function proxy(event, cb, parent, child) {
  parent[event] = function(e) {
    if (parent.contains(child) && e.target === child) {
      cb.call(this)
    }
  }
}
  1. 看代码说结果
var length = 10;

function fn() {
  return this.length + 1;
}
var obj1 = {
  length: 5,
  test1: function () {
    return fn()
  }
}
obj1.test2 = fn;
obj1.test1.call() // 11
obj1.test1() // 11
obj1.test2.call() // 11
obj1.test2() // 6
  1. 从浏览器输入Url到页面渲染发生了什么
  • 网络阶段:构建请求行、查询强缓存、DNS解析、建立TCPU连接、发送HTTP请求、响应请求
  • 解析阶段:解析html、构建dom树、计算样式、生成布局树
  • 渲染阶段:生成图层树、生成绘制列表、生成图块,优先选择视口附近的图块生成位图数据、展示内容
  1. Tcp和Udp的区别
  • 基于连接和无连接
  • 对系统资源要求(Tcp较多,UDP少)
  • Udp程序结构较简单
  • 流模式和数据包模式
  • Tcp数据保证正确性,UDP可能丢包
  • TCP保证数据顺序,UDP不保证

# 资料

原文 (opens new window)