面试总结| 字节跳动前端实习

一面

  持续了一个小时,全程都在问 CSS 和 JS。

  • 介绍 flex 布局,flex 是什么属性的缩写
      flex属性是 flex-growflex-shrinkflex-basis 的简写,当时我只答出了前两个。

  • CSS 怎么画一个大小为父元素宽度一半的正方形

    • width 设置百分比
    • padding 撑高
    • 伪元素设置 margin-top: 100%撑高(这个当时没想到,只答了前两个)
    • 如果只是要相对于 body 而言的话,还可以使用 vw 和 vh
  • 实现两栏布局的方式

    • flex
    • grid
    • table
    • float + 负 margin
  • css 的动画有哪些

    • animation
    • transition
  • transform 的属性设置顺序可以改变吗
      不可以,比如 translate 和 rotate,因为旋转后 x 轴和 y 轴也会跟着旋转,所以先平移后旋转,和先旋转后平移得到的结果是不一样的。
      既然提到了 transform,我就顺带说了 transform 的副作用。子元素的属性比如宽高等单位设置为百分比,是相对于它第一个带有定位的父元素而言的。而如果它的父元素没有设置定位但设置了 transform 的话,也能起到类似定位的效果。因此如果设置了固定定位的元素的父元素带有 transform 的话,此时它的固定定位不再是相对于浏览器视口而言的,而是相对于这个带 transform 的父元素。

  • 防抖和节流的区别,手写简易版本的防抖和节流

  • 事件委托,手写代码
      给出一个函数 fn(parent, targetTag, event, handle),parent 是要绑定事件的父元素,targetTag 是要触发事件的目标元素,event 是要监听的事件类型,handle 是监听函数。这里的主要问题在于触发元素可能是 targetTag 的子孙元素(比如 DOM 结构是 ul > li > div > span,parent 是 ul, targetTag 是 div,触发 span 也得执行 handle),所以不能单单用 e.target.tagName.toLowerCase() === targetTag 来判断,需要循环或者递归去寻找 targetTag 是否 是 e.target 的父亲节点或祖先结点。

function fn(parent, targetTag, event, handle) {
  parent.addEventListener(event, (e) => {
    e = e || window.event;
    let ele = e.target || e.srcElement;
    if(search(ele, targetTag)) {
      handle();
    }
  })
}

// 向上寻找父亲祖先节点
function search(ele, targetTag) {
  while(ele.tagName.toLowerCase() !== 'body') {
    if(ele.tagName.toLowerCase() === targetTag) {
      return true;
    }
    ele = ele.parentNode;
  }
  return false;
}

  可以戳这里进行实验

  • 模拟实现一个简易的 jQuery 的 $ 函数来获取 DOM 节点,例如 $('#a .b p'),需要取到相应的 p 标签
// 获取DOM结点
// 或者直接使用 querySelector
function get(str) {
  let ele;
  if(str[0] === '.') {
    ele = document.getElementsByClassName(str.substr(1, str.length-1));
  }
  else if(str[0] === '#') {
    ele = document.getElementById(str.substr(1, str.length-1));
  }
  else {
    ele = document.getElementsByTagName(str);
  }
  return ele;
}

// 查找target是否是parent的子孙元素
function find(parent, target) {
  // 先在document中找到所有的target,再判断它们的父亲祖先元素是否位parent
  let nodes = get(target);
  // 使用id获取结点时得到的是单个结点,使用class获取时则是一个节点集合,所以统一转换为集合的形式方便遍历
  if(nodes.length === undefined) {
    nodes = [nodes];
  }
  for(let i=0, len=nodes.length; i<len; i++) {
    let cur = nodes[i];
    // 层层遍历cur的父亲祖先节点
    while(cur.tagName.toLowerCase() !== 'body') {
      if(cur === parent) {
        return nodes[i];
      }
      cur = cur.parentNode;
    }
  }
  return undefined;
}

function _$(str) {
  let arr = str.split(' ');
  let ele = get(arr[0]);
  for(let i=1, len=arr.length; i<len; i++) {
    ele = find(ele, arr[i]);
    if(ele === undefined)  return undefined;
  }
  return ele;
}

  面试的时候我回答的思路大致如上,不过当时没有考虑很多,写的代码还有一些细节错误 Orz。当时面试官提出的问题是,比如 #a .b p,如果这个 p 标签是 .c 的孙节点的话怎么办。我就说循环或递归去找 p 标签的父亲节点,判断 .c 是否是 p 标签的祖先节点。但是面试官说如果 DOM 节点一多的话这样会很耗性能,问有没有其他的方法,我想了一会没想出来就直接说我不会了。结束的时候面试官说了句其实不用那么麻烦,只用 XXX 就够了,当时那句话我没听清楚,以为有什么 api 可以直接获取一个 DOM 节点的所有父级元素。然而现在才发现这道题其实根本不用写那么多,只需要短短的 return document.querySelector(str) 就可以了!!! querySelector 完全可以实现 jQuery 中 $ 的效果。我…

二面

  一面之后隔了十分钟左右二面的面试官就上线了,只进行了四十分钟(感觉凉凉)。一来先是常规的自我介绍(一面的时候没有自我介绍),介绍完之后直接问除了前端之外还有没有学其他的,计算机组成会吗(Orz)。我直接回答只会那么一点点,仅限于了解而已。然后面试官开始出题,0.1 + 0.2 等于多少,这个还好我之前写过一篇博客捣鼓过就直接答出来并解释一下为什么,还好面试官后面就没有再问计算机组成方面的问题了,不然可 hold 不住。

  • JS 的数据类型
  • JS 的整数是怎么表示的
      听到这个问题我有些懵,虽然问题很明确,但就是不知道这个问题是考察哪方面的问题。所以我只能牛头不对马嘴地说 JS 是弱语言类型不区分整数和浮点数云云的,结果自然是被面试官戳穿了我是在转移话题。我老实回答我 get 不到这个问题的点(因为我真的不知道要怎么回答啊,二进制?),但是面试官表示他觉得他问得已经足够明确了(听到这句话我就觉得我要凉了 Orz),如果我不知道怎么回答可以直接说不会,他接着问下一题就行。于是我就直接表示我不了解了。
  • 闭包
  • symbol 有什么用处
      可以用来表示一个独一无二的变量防止命名冲突。但是面试官问还有吗?我没想出其他的用处就直接答我不知道了,还可以利用 symbol 不会被常规的方法(除了 Object.getOwnPropertySymbols 外)遍历到,所以可以用来模拟私有变量。
  • ES6 的遍历器了解吗,symbol.iterator 是用来做什么的
      主要用来提供遍历接口,布置了 symbol.iterator 的对象才可以使用 for···of 循环,可以统一处理数据结构。调用之后回返回一个遍历器对象,包含有一个 next 方法,使用 next 方法后有两个返回值 value 和 done 分别表示函数当前执行位置的值和是否遍历完毕。
  • localstoragesessionstorageindexDB 的区别
  • 为什么用 canvas
      因为简历上写了之前用 jQuery 做的中国象棋,棋盘是用 canvas 画的。我就回答说当时想着顺带实践一下 canvas,所以就没有使用 border 来画棋盘。然而面试官说 jQuery 已经被淘汰了问我为什么还要学 jQuery,我解释说因为上学期开始学的时候还什么都不会,经常看到 jQuery 这个名字就顺带学了一点,但现在已经没用 jQuery 了。
  • 手写 bind
  • 区间排序
      面试官给了一个情景,大致的意思就是给了一个二维数组,比如 [[20, 30], [1, 10], [10, 20]],每个数组元素表示一个区间,区间之间不重叠。要求写一个函数来排序这个二维数组,使得这个二维数组表示的区间有序,例如 [[1, 10], [10, 20], [20, 30]]

  面试的时候我的思路是先将每一个数组元素的第一个值作为下标存储进一个临时数组,值为它所在原数组的索引,之后再遍历数组根据值从小到大排序。然而当时我遇到的问题是,数组元素的值是被我作为下标存进临时数组的,要怎么给这个临时数组排序?用 map ?当时我就这里想了许久也没想出来,最后因为面试官给的例子中区间的间隔是 10,所以我就赖着头皮直接从 0 开始每次累加 10 了。结果自然是被面试官戳破了,他说其实就是简单的排序而已(想桶排序那样)。然而我以为他是在考冒泡这些排序算法就往十大排序上去想解决方法,不过没想出来 Orz。之后面试官就问我有没有什么想问的,我问了我表现得怎么样有什么需要改进的吗。面试官说我面试得还不错(估计是安慰吧,我觉得我答得很糟糕啊啊啊),不过对问题的解决方法有点单一,思维没能转过来。直到现在我才理解面试官这句话的意思,因为现在我重新看这道区间排序,没想多久就想出方法了啊,直接一个 sort 函数排序就可以了啊啊啊。

function fn(arr) {
  arr.sort((a, b) => {
    return a[0] - b[0];
  })
}

let arr = [[15, 39], [0, 14], [100, 999], [80, 99], [40, 79]];
fn(arr);
console.log(arr);

  为什么当时就是没有想到 sort 函数啊 Orz,在那里瞎折腾那么久。估计也是因为这个所以二面只持续了四十分钟吧。当天下午(2019.5.31)六点多 HR 就打电话过来进行了几分钟的沟通,说我通过了前面两轮技术面,接着问了一些个人情况啥的。我问还有下一轮面试吗,HR 说没有,不过等下周会有进一步的沟通(应该是 HR 面?)。虽然是这么说,但我感觉有些虚啊,我看网上一些字节跳动的面经有好些实习生就挂在 HR 面的,评论说是综合前面的技术面才会被挂的,或者是公司找到了更合适的人选。前面两轮技术面虽然是过了,但自我感觉还有很多不足啊,特别是那两三道手写代码的题,简直了(简单的方法没想到,就想到复杂的解法 Orz)。哎,还是等下周 HR 面后看结果吧,估计也还得等一个多星期才能出最后结果,到时再来补充吧(但愿能过 🙏)。

人生中的第二个offer

2019.6.3:

  啦啦啦,本来以为这周会有 HR 面的,结果中午刚放学就接到了 HR 的电话。看到那从北京打来的电话号码的时候我心一紧,以为是 HR 面来了。结果刚接电话 HR 就问我有没有时间,要进行五分钟左右的沟通。我有些惊讶于 HR 面难道只需要五分钟。结果就被 HR 接下来的一句 “你已经通过了 offer 审批,现在准备发录取邮件” 给吓到了。没有 HR 面的??接着就确定了下入职时间,本来预期 7 月 6 号入职的,不过因为公司周末不办入职手续,所以就推到 8 号星期一再入职啦。接着又询问了一些信息就愉快又兴奋地结束通话啦。

  下午又给 HR 发信息问了一些情况,待遇、上班时间啥的,不得不说字节跳动的待遇真的好好啊啊啊!!弄得我都不想回来上学只想在那边实习了。预计会实习三个月左右吧,应该会请一个月的假,大概国庆假期过后就回学校,目前我是这么打算的,HR 也说需要实习三个月。开心过后麻烦就来了,在北京那租房好像很麻烦啊,押一付三啥的,还要找人合租,不然一个人住房租可 hold 不住。希望可以尽快找到合适的房子和室友啊!不然到时还没找到房子就更麻烦了。

  这个七月,帝都 🛫🛫🛫

  真是让人期待啊~

  冲鸭!!!


 上一篇
elementUI级联选择器踩坑 elementUI级联选择器踩坑
发现问题  今天使用 elementUI 的时候踩到坑了,期望的效果如下图所示。每一栋教学楼都有 1-7 层,每一层的教室都为 03-22,以此来选择不同的教室。   参照官方文档,我写了如下的级
2019-06-14
下一篇 
JavaScript:十大排序的算法思路和代码实现 JavaScript:十大排序的算法思路和代码实现
  本文内容包括:(双向)冒泡排序、选择排序、插入排序、快速排序(填坑和交换)、归并排序、桶排序、基数排序、计数排序(优化)、堆排序、希尔排序。大家可以在这里测试代码。更多 leetcode 的 JavaScript
2019-05-28
  目录