首页 > 字节跳动企业应用前端日常实习一二面面经
头像
🍉🔪白告
发布于 2021-07-06 23:27
+ 关注

字节跳动企业应用前端日常实习一二面面经

(零基础开始自学前端4个月,一面试就千疮百孔)
(每一场问题都不多,主要是写代码,感觉是我太墨迹了的关系)

一面(7.05)

1. 你说你读过vue的源码,对什么比较熟悉,有过自己的理解和实践(我回答了响应式那块,然后就让我写一下,这个我当时自己有准备过所以还好)
// 发布者,订阅中心
class Dep {
  constructor() {
    this.subs = [];
  }
  // 此处的sub是依赖收集时,Dep.target也就是当前正在执行的watcher
  addSubs(sub) {
    if (this.subs.indexOf(sub) < 0) {
      this.subs.push(sub);
    }
  }
  notify() {
    this.subs.forEach(item => item.update())
  }
}
Dep.target = null;

// 订阅者
class Watcher {
  constructor(obj, key, updateCb) {
    this.data = obj;
    this.key = key;
    this.updateCb = updateCb;
    this.value = this.get()
  }
  get() {
    Dep.target = this;
    this.value = this.data[this.key];
    Dep.target = null;
    return this.value;
  }
  update() {
    const oldValue = this.value;
    const newValue = this.get();
    this.updateCb(newValue, oldValue);
  }
}

// observer类 劫持数据
class Observer {
  constructor(obj) {
    this.data = obj;
    if (this.data == null || typeof this.data !== "object") {
      return;
    }
    if (Array.isArray(this.data)) {
      this.observeArray();
    } else {
      this.walk();
    }
  }
  walk() {
    for (let i in this.data) {
      this.defineReactive(this.data, i);
    }
  }
  observeArray() {
    for (let i = 0; i < this.data.length; i++) {
      observe(this.data[i]);
    }
  }
  defineReactive(obj, key) {
    let val = obj[key];
    observe(val);
    const dep = new Dep();
    Object.defineProperty(obj, key, {
      get() {
        if (Dep.target) {
          dep.addSubs(Dep.target)
        }
        return val;
      },
      set(newVal) {
        if (newVal === val) {
          return;
        }
        val = newVal;
        observe(val);
        dep.notify();
      }
    })
  }
}
// 数据监测方法
function observe(data) {
  new Observer(data);
}

// 写一个最简单的例子
const obj = {
  a: 1
};
observe(obj);
new Watcher(obj, "a", (newVal, oldVal) => {
  console.log("newVal", newVal);
  console.log("oldVal", oldVal + '\n');
});
obj.a = 2;
obj.a = 3;
2. 你的项目里有实现过分页组件么,写一个试试(我一开始理解错了以为是下拉加载后端的分页请求,意识到错了后改提了吸顶组件和懒加载图片等)
然后就写了下吸顶组件:(当时写的时候很紧张,复盘的时候都代码看不下去了)

<template>
  <div class="sticky" :style="Position">
    <div class="sticky-wrap">
      <slot></slot>
    </div>
  </div>
</template>

<script>
export default {
  name: "sticky",
  data() {
    return {};
  },
  computed: {
    Position() {
      var position = this.support("position", "sticky")
        ? "sticky"
        : "relative";
      return "position:" + position;
    },
  },
  mounted() {
    if (this.support("position", "sticky")) {
        return;
      }
      const sticky = this.$el;
      const Wrap = this.$el.querySelector(".sticky-wrap");
      const util = new IntersectionObserver((entries) => {
        entries.forEach(entry => {
            if (entry.isIntersecting) {
              Wrap.style.position = 'absolute'
            } else {
              Wrap.style.position = 'fixed'
            }
        })
      }, {
        // 这个参数忘记了,大概是目标元素的可视比例
      })
      util.observe(Wrap)
  },
  methods: {
    support(attr, value) {
        // 主要是测试是否兼容sticky
    }
  },
};
</script>
3. setValue(obj, key, value) 输入 a.b.c.d    (当时原题的key是“a[0].b[1].c”这种,因为key是字符串,看我一下没头绪就简化了一下,我太菜了,简化后就比较简单实现了,key做split处理,for循环遍历下去,像前缀树一样最后赋值)
输出:
var a = {};
setValue(a, "b.c", 10);
a = {
  b: {
    c: 10
  }
}
4. 什么是BFC,如何触发BFC,应用场景
5. 实现debounce函数(终于来了道秒杀题,分立即执行和延迟执行)
function debounce(fn, wait, immediate) {
    let timer = null
    return function () {
        let context = this
        let args = arguments
        if (timer) clearTimeout(timer)
        if (immediate) {
            let call = !timer
            timer = setTimeout(() => {
                timer = null
            }, wait)
            if (call) fn.apply(context, args)
        } else {
            setTimeout(() => {
                fn.apply(context, args)
                timer = null
            }, wait)
        }
    }
}
6. 遍历dom树并打印相应路径
    <div id="root">
      <p>p1</p>
      <span>
        <span>span2</span>
      </span>
      <p>p2</p>
    </div>
(当时最后时间不够了,大致雏形能出来,中间dom操作姑且看作是伪代码)
traverse(document.getElementById('root'));
=>
["DIV"]
["DIV", "P"]
["DIV", "SPAN"]
["DIV", "SPAN", "SPAN"]
["DIV", "P"]

function traverse(root) {
  let res = []
  function dfs(root, queue) {
    queue.push(root)
    console.log(queue)
    if (!root.childNodes) {
      res.push(queue)
      queue = [root]
      return
    }
    const childs = root.childNodes
    for (let item in childs) {
      dfs(item, queue)
    }
  }
  dfs(root, [])
  return res
}
最后时间来不及了,提问环节我征求了下面试官小哥的建议,鼓励了一下我,代码能力还需要加强
-----------------------------------------------------------------------------------------------------------------------------

二面(7.06 严重怀疑自己)

1. 笛卡尔乘积: fn([['a', 'b'], ['n', 'm'], ['0', '1']]) => ["an0", "an1", "am0", "am1", "bn0", "bn1", "bm0", "bm1"]
(我拘泥于用reduce来写,结果忘了API格式一直报错,下来复盘时稍微一改就对了)
function fn(arr) {
  return [].reduce.call(arr, (pre, next) => {
    let res = []
    pre.forEach(a => {
      next.forEach(b => {
        let temp = '' + a + b
        res.push(temp)
      })
    })
    return res
  })
}

console.log(fn([
  ['a', 'b'],
  ['n', 'm'],
  ['0', '1']
]))
2. 实现u.console("breakfast").setTimeout(3000).console("lunch").setTimeout(3000).console("dinner")
(这道题卡了一会儿,被提示用promise后又写了一会儿,直接用Promise.prototype.setTimeout这样写一直没实现延时功能,无奈先跳过了,下来复盘才开窍)
// 其实也就是链式调用延时器实现sleep效果:breakfast -> 3s后 -> lunch -> 3s后 -> dinner
class U {
  constructor() {
    this.queue = Promise.resolve()
  }
  console(str) {
    this.queue = this.queue.then(() => {
      console.log(str)
    })
    return this
  }
  setTimeout(wait) {
    this.queue = this.queue.then(() => {
      return new Promise((resolve, reject) => {
        setTimeout(() => {
          resolve()
        }, wait)
      })
    })
    return this
  }
}

let u = new U()
3. tcp和udp的区别(常见八股文)
4. 原型链题,看输出
var A = function () {};
A.prototype.n = 1;
var b = new A();
A.prototype = {
  n: 2,
  m: 3
};
var c = new A();

console.log(b.n);  // 1
console.log(b.m);  // undefined
console.log(c.n);  // 2
console.log(c.m);  // 3
5. 事件循环,将async await改写为promise形式,再判断输出顺序
async function async1() {
  console.log('async1 start')
  await async2()
  console.log('async1 end')
}
async function async2() {
  console.log('async2')
}
console.log('script start')
setTimeout(function () {
  console.log('setTimeOut')
}, 0)
async1()
new Promise(function (resolve) {
  console.log('promise1')
  resolve()
}).then(function () {
  console.log('promise2')
})
console.log('script end')

// 改写:
function async1() {
    return new Promise((resolve, reject) => {
        console.log('async1 start')
        async2()
        resolve()
    }).then(() => {
        console.log('async1 end')
    })
}

function async2() {
    return new Promise((resolve, reject) => {
        console.log('async2')
                resolve()
    })
}

// 输出顺序:
script start
async1 start
async2
promise1
script end
async1 end
promise2
setTimeOut
反问环节同样也是建议我多去写项目锻炼代码能力,问了下部门是属于B端还是C端,解释说是B端,但实际从工作角度上来讲应该属于C端
今天二面结束时我的内心是平静的,一个小时时间就只进行了5道问题,应该是凉了,7点HR发来消息称二面通过,希望好运吧,因为面试经验少太容易紧张,需要再磨砺自己

更多模拟面试

全部评论

(6) 回帖
加载中...
话题 回帖

推荐话题

相关热帖

历年真题 真题热练榜 24小时
技术(软件)/信息技术类
查看全部

近期精华帖

热门推荐