字节跳动EE部门前端面试经历及总结
目录
前言
上次面试面经的链接
楔子
正文
面试前做出的准备
面试前奏
面试高潮
面试尾声
小技巧
总结
笔试方面
面试方面
前言
你好,我是星辉,幸会幸会。
今天下午我参加了字节跳动EE部门的前端视频第一次面试,把它记录总结下来,希望能够对大家带来帮助。
上次面试面经的链接
字节跳动前端面试经历及总结
楔子
在准备前面文章中所说的前端面试的时候,听说字节跳动的EE部门在学校开宣讲会并进行笔试,抱着试一试的态度和记录一下题型为接下来的面试做下准备的心态就和我的小伙伴一起去参加了笔试。
EE部门即效率工程(efficiency engineer),为字节跳动公司创造提升公司效率工具的部门。
听着宣讲,心里开始活络了起来。哇,这个部门好适合我,我在平时生活中就是一个注重效率的人,EE在公司中有些提升效率的方法我也用过。
然后笔试,前后端混合考,听朋友说,考的是算法竞赛的一些题,总体来说是不会的。
然后…笔试就通过了,我想应该是对前端算法的要求比较低的缘故,不过我也把笔试总结在小技巧了。
正文
面试前做出的准备
我在面试前准备以下几点东西,似乎没有解决到面试的任何问题
在网上搜集总结了操作系统和数据库的面试题放到了博客,方便面试前的复习
将上次的面试的自我介绍改了改,把三段经历改成了重效率等的品质,方便紧扣EE部门的理念
看了上一次的前端面试总结,保证上次面试问的问题还能够做对
看了博客里总结的其他面试题目,保证考试的时候都能够答上来
面试前奏
这次面试和上一次不同,不再是用牛客网的连接了,使用的是视频会议室zoom。还在看博客,叮咚,面试官上线了。
这次面试官没有开视频,我无法通过视频得到面试官即时的情绪反馈,说话开始变得语无伦次,说着说着就想尽快终止了,自我介绍刚开始就崩盘。
面试高潮
来了来了,直接就开始问技术的问题了。
谈谈居中,垂直居中和水平居中
很基础的css题目,我把我脑中的几种情况有条理的给说明了一下,具体可见上一篇前端面经。当我慢慢心态放下的时候,面试官说“还有么,还有其他的解决方案么,这些我在实战的时候都不常用。而且你说的最后一个方法是你真实的用过呢还是在网上查的记忆的呢”“这…没有了,最后一种是在网上记忆的,但前面的那些方法都是我在实战中遇到过的。”
css,你还有什么要补充的么?
慌了,这种开放性题目把我问慌了,头脑里没有东西。“没有补充了,我平时用到的css就是基础的实战代码”。
后来反思这个问题可以吸引面试官的亮点是考虑web 的响应式以及兼容性。
移动端响应设计
<meta name="viewport" content="width=device-width, initial-scale=1.0">
// 绝对像素单位变为rem相对单位
px=>rem
1
2
3
4
响应式图片web设计
// 保持高宽比
// 使用width属性
img {
width: 100%;
height: auto;
}
// 使用max-width属性
img {
max-width: 100%;
height: auto;
}
// media query 不同设备显示不同图片和样式
/* For width smaller than 400px: */
body {
background-image: url('img_smallflower.jpg');
}
/* For width 400px and larger: */
@media only screen and (min-width: 400px) {
body {
background-image: url('img_flowers.jpg');
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
js你知道的都有哪些数据类型?
原始类型:字符串、数字、布尔
特殊类型:Null、Undefined
对象类型:数组、对象
聊聊NaN
NaN和任何值都不相等,包括自身。可以通过x!=x来判断变量x是否为NaN,当且仅当x为NaN的时候,表达式的结果才为true。函数isNaN()的作用与此类似。
什么样的数据值在判断时会被转换为false
false、undefined、null、0、-0、NaN、[]
所有其他值,包括所有对象都会转换成true
对null执行typeof操作返回什么
返回字符串"object"
通常认为null是它自有类型的唯一成员,可以表示数字、字符串和对象是“无值”的
对undefined执行typeof操作返回什么
返回字符串"undefined"
null和undefined的比较
相同点:都表示“值的空缺”,相等运算符"=="认为两者是相等的,两者都可以转化为false,不包含任何属性和方法
不同点:严格相等运算符"==="认为两者是相等的
1
2
加号运算符和比较运算符的隐性转换
加号运算符更偏爱字符串,如果它的其中一个操作数是字符串的话,则进行字符串连续操作
比较运算符更偏爱数字,只有在两个操作数都是字符串的时候才进行字符串的比较
arguments是数组么
arguments对象不是数组。arguments 是一个对应于传递给函数的参数的类数组对象。
Arguments定义
arguments 是一个对应于传递给函数的参数的类数组对象。
描述
arguments对象不是一个 Array 。它类似于Array,但除了length属性和索引元素之外没有任何Array属性。例如,它没有 pop 方法。但是它可以被转换为一个真正的Array。
// 转化真正的数组
var args = Array.prototype.slice.call(arguments);
var args = [].slice.call(arguments);
// ES6使用Array.from()方法或扩展运算符将参数转换为真实数组
var args = Array.from(arguments);
var args = [...arguments];
1
2
3
4
5
6
对参数使用 typeof
返回 ‘object’
它类似于Array,但除了length属性和索引元素之外没有任何Array属性。例如,它没有 pop 方法。但是它可以被转换为一个真正的Array。被称为类数组。
ES6和ES5有什么区别
1. 引用块级作用域的概念,可使用let命令和const命令
2. 数组的解构赋值(ES6允许按照一定模式,从数组和对象中提取值,对变量进行赋值,这被称为解构。)
3. 字符串的拓展(模板字符串,新增includes()等方法)
4. 数值的拓展(ES6 将全局方法parseInt()和parseFloat(),移植到Number对象上面,行为完全保持不变,这样做的目的,是逐步减少全局性方法,使得语言逐步模块化)
5. 数组的拓展(数组的拓展运算符,新增Array.from()等API)
6. 对象的拓展(属性简洁表示,对象的拓展运算符,对象的合并等)
7. 函数的拓展(参数默认值,参数解构赋值,剩余操作符,箭头函数)
8. Promise对象
9. async函数
10. class类(super关键字)
11. Module的语法(export和import命令)
1
2
3
4
5
6
7
8
9
10
11
算法问题:如何实现在n个数里找到两个数和为sum
Promise的用法
function timeout(ms) {
return new Promise((resolve, reject) => {
setTimeout(resolve, ms, 'done');
});
}
timeout(100).then(console.log)
1
2
3
4
5
6
7
Promise设计思想
所有异步任务都返回一个 Promise 实例。Promise 实例有一个then方法,用来指定下一步的回调函数。
Promise作用
Promise 对象起到代理作用,充当异步操作与回调函数之间的中介,使得异步操作具备同步操作的接口。
Promise好处
把执行代码和处理代码分离开,使异步操作逻辑更加清晰。
Promise状态
Promise对象代表一个异步操作,有三种状态:
初始状态:pending
操作成功:fulfilled
操作失败:rejected
Promise特点
对象的状态不受外界影响:只有异步操作的结果可以决定当前是哪一种状态,其他操作都不会影响状态改变
一旦状态改变,就不会再变
Promise优缺点
优点
可以将异步操作以同步操作的流程表达出来,避免了层层嵌套的回调函数
对象提供统一的接口,使得控制异步操作更加容易
缺点
无法取消 Promise,一旦新建它就会立即执行,无法中途取消
如果不设置回调函数,Promise内部抛出的错误,不会反应到外部
当处于Pending状态时,无法得知目前进展到哪一个阶段
Promise和其他的比较
// 正常任务
setTimeout(function() {
console.log(1);
}, 0);
// 微任务
new Promise(function (resolve, reject) {
resolve(2);
}).then(console.log);
// 同步任务
console.log(3);
// 3
// 2
// 1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Promise,then和async,await有什么区别
async函数是什么
async 函数就是 Generator 函数的语法糖。
Generator函数写法
let promise = function (val){
return new Promise(function (resolve, reject){
setTimeout(()=>{
console.log(val);
resolve(val);
},1000);
});
};
let gen = function* (){
let p1 = yield promise('1');
let p2 = yield promise('2');
};
let genF = gen();
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
async函数写法
let promise = function (val){
return new Promise(function (resolve, reject){
setTimeout(()=>{
console.log(val);
resolve(val);
},1000);
});
};
let gen = async function (){
let p1 = await promise('1');
let p2 = await promise('2');
};
1
2
3
4
5
6
7
8
9
10
11
12
13
async/await注意点
async用来申明里面包裹的内容可以进行同步的方式执行,await则是进行执行顺序控制,每次执行一个await,阻塞代码执行等待await返回值,然后再执行之后的await。
await后面调用的函数需要返回一个promise。
await只能用在async函数之中,用在普通函数中会报错。
await命令后面的Promise对象,运行结果可能是rejected,所以最好把await命令放在try…catch代码块中。
不使用class用function定义一个对象并实现继承(写代码)
// 原型链的方式
// 用function定义对象
function Person(name, age) {
this.name = name
this.age = age
this.say = function() {
console.log(this.name)
console.log(this.age)
}
}
// 新对象继承Person
function Man(name,age) {
this.name = name
this.age = age
}
Man.prototype = new Person()
Man.prototype.speak = function() {
console.log("你好啊")
}
var m = new Man('hv',20)
m.say()
// apply方法的方式
function ClassA(name){
this.name = name;
this.sayName = function(){
console.log(this.name);
}
}
function ClassB(name,age){
ClassA.apply(this,arguments);
this.age = age;
this.sayAge = function (){
console.log(this.age);
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
你对闭包的理解是什么
闭包就是能够读取其他函数内部变量的函数。
闭包的用途:可以读取函数内部的变量,并且让这些变量的值始终保持在内存中。
// 输出全为10
for(var i=0;i<10;i++){
setTimeout(function(){
console.log(i);
},50);
}
// 输出相应的输出
for(var i=0;i<10;i++){
(function(i){
setTimeout(function(){
console.log(i);
},50);
})(i);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
你用过bind()方法么
用过,以下是我用bind方法的情形。
// 如果你引用一个方法,它将失去和对象的连接
> var func = jane.describe;
> func()
TypeError: Cannot read property 'name' of undefined
// 解决办法是使用函数内置的bind()方法。它创建一个新函数,其this值固定为给定的值。
> var func2 = jane.describe.bind(jane);
> func2()
'Person named Jane'
1
2
3
4
5
6
7
8
9
function f(y) {return this.x + y}
var o = {x : 1}
var g = f.bind(o)
console.log(g(2))// 3
1
2
3
4
请用画图工具介绍一下盒子模型
宽度和真实占有宽度,不是一个概念!
CSS盒模型和IE盒模型的区别:
在 标准盒子模型中,width 和 height 指的是内容区域的宽度和高度。增加内边距、边框和外边距不会影响内容区域的尺寸,但是会增加元素框的总尺寸。
box-sizing: content-box; // 在宽度和高度之外绘制元素的内边距和边框。内容盒模型
IE盒子模型中,width 和 height 指的是内容区域+border+padding的宽度和高度。
box-sizing: border-box; // 通过从已设定的宽度和高度分别减去边框和内边距才能得到内容的宽度和高度。IE盒模型
1
2
3
4
5
对象的引用知识点
// 基本类型:值相同即可
var a = 5
var b = 5
console.log(a == b) // true
// 对象类型:值和引用都相同才可
var a = [1,2,3]
var b = [1,2,3]
console.log(a == b) // false
// 修改b的同时也在修改a
var a = [1,2,3]
var b = a
console.log(a == b) // true
1
2
3
4
5
6
7
8
9
10
11
12
13
14
箭头函数是什么
箭头函数的定义
箭头函数相当于匿名函数,并且简化了函数定义。
// 箭头函数
x => x * x
// 相当于下面的函数
function (x) {
return x * x;
}
1
2
3
4
5
6
7
调用形式
var fn = x => x * x
console.log(fn(4))
1
2
箭头函数的两种格式
只包含一个表达式,连{ … }和return都省略掉了
包含多条语句,这时候就不能省略{ … }和return
x => x * x
x => {
if (x > 0) {
return x * x;
}
else {
return - x * x;
}
}
// 如果参数不是一个,就需要用括号()括起来
(x, y) => x * x + y * y
1
2
3
4
5
6
7
8
9
10
11
12
13
箭头函数的好处
箭头函数完全修复了this的指向,this总是指向词法作用域,也就是外层调用者obj
面试尾声
此次面试你对我们公司还有什么问题么,我可以回答你两个问题
于是我问了部门对字节跳动的效率优化案例,但面试小哥说不好透露这些东西。
我又问了如果我再来面试应该再准备些什么,“提升基础,让自己的能力在基线以上。”
小技巧
笔试的小技巧
考试不会写也要尽量把卷子给写满
题目不会写代码的话尽量往上面写代码思路
总结来说,“会就多写,不会就瞎比比”
笔试通过后我总结了一下,发现学校所教众多能力也不是不无用处。我想我笔试通过上面两项能力起到了至关重要的作用。
总结
笔试方面
重视算法和数据结构,可以考虑适度的研究一些算法竞赛题里面的经典题目
重视算法的复杂度,数据量比较大的题目条件下一定要重视算法复杂度,否则可能程序难以运行
笔试认真写,时间还是挺吃紧的,注意把握好时间,把能写部分先给写了
面试方面
遇到问题不要抢答,慢慢来,静静的思索一下再作答,拿笔画一下,跟问题相关的都可以写在纸上,不要什么也不写
重视js基础和基本的算法,可以把js权威指南和高级js教程给研究一下,把js基础把握好。通过leetcode和牛客网学习算法基础。
上一次面试是碰巧问了你一些比较简单的问题,没有暴露出来js基础薄弱的问题,需要总结一下常见的js面试题。
---------------------
作者:__失心疯__
原文:https://blog.csdn.net/y_silence_/article/details/85145905
版权声明:本文为博主原创文章,转载请附上博文链接!