字节一面 酣畅淋漓的体验 心情五味杂陈 有欣喜有悲伤

1,902 阅读11分钟

字节一面 认识到自己的不足,好好学习,继续赶路

哈喽哈喽,我是你们的金樽清酒。最近沉浸在面试当中,想找到一个心仪的公司去好好提升一下自己的实力。但是在某一天晚上,很突然的收到了字节的面试邀请,我这心里的压力一下子就上来了,字节是我一直想去的公司,我是想晚点修炼好自己再去的,现在也只有面对了,没有一定准备好的时候,只有硬着头皮往前冲。不过通过这次面试更加坚定了我的想法。

面试题目

  • 自我介绍 首先是简单的自我介绍。我是xxx大学的学生,有哪些优势。学习过哪些技术栈。如何去学习这些技术栈的。引用别人的自我介绍公式就是说:"我是谁,我来自哪里,我有什么优势,为什么能够胜任这份工作"。 这是很好的展示自己的机会,这个时候就不要谦卑了,会什么就说什么,当然,做人肯定要脚踏实地,不能弄虚作假,不要连自己都没有底气,这是自己的一种软实力吧,学习就是追求一个真实和踏实。

  • 你为什么学习前端,你是怎么学习前端的? 这个问题是很多公司都喜欢问的问题,你为什么会选择前端呢?其实吧,也是对前端有兴趣,爱因斯坦说过,兴趣是最好的老师。从小我就觉得程序员是一个很酷的职业,面无表情哐哐哐就能黑进别人的电脑。哈哈哈哈哈哈哈,可能那是网络安全方面,跟前端完全不搭边,但是在上过学校的课之后,发现我并不喜欢网络工程,而是可视化的前端更加吸引我,虽然不能哐哐哐黑电脑,但是可以哐哐哐的敲出页面,这也是特别帅气的好不好。再加上有学长的带路,看到学长进了字节,我也想跟上学长的脚步,根据学长提供的方法去进行学习。

怎么学习前端的?找大神的课去看。看大神的课就有一种站在巨人的肩膀上的感觉。有一句话是这么说的你可能苦思冥想一个东西,在网上一找发现,很久以前就有人提出来了,更或者比你自己的更加的先进,所以集思广益,虚心的向大佬请教,踏实的自己去体验,去品读源码,不要只停留在会用的层面,还要知道怎么来的,看到源码里面那些优雅的代码,你也会忍不住的感慨,这也是提升代码水平的方法。而且了解它的构造你能更好的去使用。还有一个很好的方法就是写文章,把自己学到的知识总结起来,进行输入输出,这样学到的东西很牢固,也跟大家一起分享交流。

  • js基础题

1.箭头函数与普通函数的区别? 首先,箭头函数用箭头表示,且箭头函数都是匿名函数,而普通函数可以是具名函数,也可以是匿名函数。在外形上有区别,写法更加的简便。

//普通函数
function a(){
console.log("普通具名函数")
}
let a=function(){
console.log("普通匿名函数")
}

//箭头函数
let a=()=>{
console.log("箭头函数")
}

2.普通函数可以通过new来构造实例,那箭头函数可以用new来构造实例嘛? 答案是不能。要解决这个问题,我就得知道new这个关键字到底做了什么事情? new一个构造函数会发生以下几件事情

  • 1.创建一个空对象
  • 2.将空对象得prototype属性指向构造函数的prototype。
  • 3.将this指针指向obj
  • 4.判断函数的返回值类型,如果是值类型,返回创建的对象。如果是引用类型,就返回这个引用类型的对象 从new的过程来看,箭头函数都没有this指针,所以是不能成为构造函数,被new得到实例对象的。

3.普通函数的this它是取决于什么? 关于普通函数this指向的问题,有几条规则,可以看我的文章。 (js 当中的this关键字很难? 记住这几条规则就够了 - 掘金 (juejin.cn)) 这里我就不再过多的赘叙了。

4.用call,bind,applay能不能改变箭头函数的this指针的方向? 箭头函数的 this 永远指向其上下文的 this ,任何方法都改变不了其指向,如 call() , bind() , apply(),因为箭头函数没有产生this。

5.什么是闭包? 在js中,根据词法作用域的规则,内部函数总是可以访问外部函数中的变量的,当通过调用一个外部函数返回一个内部函数后,即使外部函数已经执行完毕,但是内部函数引用了外部函数中的变量,依然会保存在内存中,我们把这些变量的集合叫做闭包。 缺点:内存泄漏(调用栈里面的可用空间变小了)

我感觉闭包是一个很难懂的问题,建议小伙伴们多去了解一下闭包。

6.闭包可以解决一些什么问题? 1.创建私有变量 (全局变量不易维护) 2.延长变量的生命周期 3.实现柯里化(颗粒化)

7.简单介绍一下垃圾回收机制,就是怎么知道哪些需要回收,哪些不需要回收。

垃圾回收机制,是一种自动的检测和清除没有用的对象,来腾出内存空间。垃圾回收机制可以防止内存泄漏和提高程序的性能,js语言中的垃圾回收机制是浏览器自动执行的。

垃圾回收机制的算法

引用计数:通过跟踪每个对象的计数,来确定这个对象是否需要被回收。 标记清除:通过算法标记这些没用的对象,然后再清除这些对象。 标记整理:和标记清除一样的标记,但是在清除阶段会移动对象位置,统一的进行压缩。

垃圾回收机制,算是给自己挖的一个坑吧,因为自己也不太了解垃圾回收机制,所以大家看的时候仅供参考,再去找文章深入的了解一下。

8.var const let 作用域的区别?(我觉得这个巨坑,越是基础就越难) const 和 let 是ES6新增的。当用let 和cost加上花括号的时候,就会产生一个块级作用域,不会让内部变量跑到外部去,可以让变量私有化,不会造成变量的污染。而var会声明提升,变量会跑到全局去。

9.const 是常量,那么定义完之后可以修改值嘛? 这个问题,我在上一家公司也碰到过,上上家也碰到过,对于这个问题,也是这一面后才理解透彻,也是字节面试官的循循善诱。对于上两家公司我是这么回答的,一个是可以修改,我记得某些情况下可以修改的。第二家公司我是这样回答的,修改不了。

对于字节,我是这样回答的。修改不了,我记得const是常量,一定义就修改不了。常量必须初始化。 字节面试官:那我用const 定义一个对象,然后修改属性里面的值,可以修改嘛。我记得是可以修改的,哦,那引用类型可以修改,原始数据类型不可以修改。其实const是能够修改对象的属性,但是不能修改它的引用地址。

关于这个问题,小伙伴们有没有更标准的答案呢?欢迎留言评论。

10.v-if和v-show的区别? v-if会导致dom结构直接消失,而v-show是通过让css样式消失,然后dom结构仍然存在。是通过display:none来实现的。

  1. css隐藏元素的方式(经典考题)
  2. display: none 脱离文档流 无法响应事件 回流重绘
  3. visibility: hidden 占据文档流 无法响应事件 重绘
  4. opacity: 0 占据文档流 响应事件 重绘 || 不重绘
  5. position: absolute 脱离文档流 无法响应事件 回流重绘
  6. clip-path: circle(0%) 占据文档流 无法响应事件 重绘

这些方式可以有些会回流重绘,有些会重绘,有些可以操作dom结构,有些不可以操作dom结构。、 这就需要我们对每一种方式的特性有一些了解。

11.透明度为零,隐藏dom,还能触发点击事件嘛? 从上面我们可以看到,opacity:0是占据文档流的,所以肯定是可以触发点击事件的。

12.vue里面有响应式,在一个函数里面,同时修改了多个响应属性,比如this.a=1,this.b=2,this.c=3,那么会渲染几次? 为什么只会执行一次? 三个都在settimeout里面修改几次? 如果都在promise.then里面会修改几次?(这道题目整吐了)

这一道题就留给掘友吧。我自己再去研究一下。

13.组件间通讯有多少种方法,有多少种写多少? 1.父子组件通信 子组件props接受 用definedProps接受父组件传过来的值 2.子父组件通讯 子组件通过emit发布一个事件,父组件订阅该事件。 3.子父通讯 子组件拿到父组件的数据并修改后emit出来,父组件靠v-model实现双向绑定 4.子父通讯 子组件definedExpose暴露出来值,父组件利用ref读取子组件暴露的值 5.父子通讯 provide父组件 reject子组件 常见的父子组件通讯的方式 6.EventBus 事件总线 mitt插件来实现 首先把该文件引入到同一个js,然后得放在生命周期中使用 7.vuex/pinia

  1. provide/reject是响应式的嘛? 我的回答是响应式的,但是好像不对,有掘友解释一下嘛?

15.v-model是一个语法糖,底层实现的原理?其实也就是props加emit的那种方式,那props的key是什么?(汗流浃背)

这一道题我也汗流浃背,我知道v-model是常考题,一般问v-model的底层原理,在input框中双向绑定,用于组件传值的不大清楚。

  • 代码考核

第一题事件循环机制(我放一道百度笔试题吧,大体一样)

setTimeout(function () {
    console.log('setTimeout 1');
    new Promise(function (resolve) {
        console.log('promise 1');
        resolve();
    }).then(function () {
        console.log('promise then')
    })
})
async function async1() {
    console.log('async1 start')
    await async2();
    console.log('async1 end')
    await async3();
}
async function async2() {
    console.log('async2')
}
async function async3() {
    console.log('async3')
}
console.log('eventLoop');
async1();
new Promise(function (resolve) {
    console.log('promise 2');
    resolve();
}).then(function () {
    console.log('promise2 then')
});
new Promise(function (resolve) {
    console.log('promise 4');
    resolve();
}).then(function () {
    console.log('promise4 then')
});
console.log('eventLoop end');

输出执行的顺序,并分析怎么输出的。 这个就是考验的事件循环,很简单的,先同步代码,遇到微任务进队列,遇到宏任务进队列。同步执行完再微任务出队,然后宏任务出队,如此反复。

第二题

var a=1
function b(){
console.log(a)
var a=2
console.log(a)
}

说出打印结果 undefined 和2 请掘友分析一下为啥。

第三题 数组变成树。按照子父节点。 这题网上出现过很多。

第四题 版本号排序 将版本号数组排序'1.2','1.34','1.4','3.3.3.3.3.3','6.2' 注意版本号在日常维护中很重要,一般很小的改动版本号加0.01,再大一点加0.1,如果是很大的改动那就版本号加一。1.34是比1.4要大的,可以理解为34个版本。

对于算法弱的我来说,无疑是挂在了算法上,收到了字节的感谢信,进人才库了。但是从这次面试我也认识到了自己还有很多的不足,只要发现了问题所在,那就是一次成功。而且我发现字节也并不是高不可攀,希望再准备一段时间,再战字节。最后说一句,面试官人真的蛮有耐心的,会引导我去解决问题,还会给我解释一些问题,这就是大厂的修养,也让我更加想跟这些优秀的人做同事,趋之若鹜。