热乎乎的字节跳动面经(一面二面)

两面面经放在一起拉,大家加油哦,如果觉得有用的话可以帮我点个赞啦!!!(同时欢迎关注我的微信号:@大明前端)
1. ES6 语法: 解构赋值,模板字符串,promise,let,const,默认参数....
```javascript
const obj = {a : 1, b : 2};
const {a, b} = obj; // a = 1; b = 2;
```
2. 说一下react和vue在状态更新,组件间通信,DOM渲染的异同,这个要对这两个框架都很熟悉,这个我没答好,给大家推荐一篇文章哈哈哈。
https://blog.csdn.net/Tokki_/article/details/90726563?ops_request_misc=%25257B%252522request%25255Fid%252522%25253A%252522160976102016780299044916%252522%25252C%252522scm%252522%25253A%25252220140713.130102334..%252522%25257D&request_id=160976102016780299044916&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~sobaiduend~default-2-90726563.first_rank_v2_rank_v29_unweighted&utm_term=react%E5%92%8Cvue%E7%9A%84%E5%8C%BA%E5%88%AB%E5%8F%8A%E4%BC%98%E7%BC%BA%E7%82%B9

3. 封装一个promise.all;

```javascript
function all(promises) {
const values = [];
return new Promise((resolve, reject) => {
promises.forEach((promise, index) => {
promise.then(value => {
values.push(value);
if(values.length == promises.length){
resolve(values);
}
}, error => { reject(error) });
})
})
}
```
4. 手写36进制加法: (这个字节很喜欢考!!!) 我自己之前碰到过一次,现在又碰到了!!!
function add(a, b) {}   // "1" + "1z" = "20";
// "1b" + "1" = "1c";
下面我给出参考代码:希望各位
```javascript
function add(a, b) {
let dictMap = ['0', '1', '2', '3', '4', '5', ......, 'z'];
let str1 = a.split("").reverse(); // ["z", "1"]
let str2 = b.split("").reverse();// ["1"]
let aLen = a.length, bLen = b.length, len = (aLen > bLen ? aLen : bLen) + 1;
let sum = new Array(len).fill(0);
for(let i = 0; i < aLen; i++) {
sum[i] = dictMap.indexof(str1[i]);// [0, 0, 0] => [35, 1, 0];
}
for(let j = 0; j < bLen; j++) { // [1]
sum[j] += dictMap.indexof(str2[i]);// => [36, 1, 0];
}
// 进位
for(let i = 0; i < sum.length-1; i++) {
if(sum[i] > 35) {
sum[i] %= 36;
sum[i+1] += (sum[i] / 36); // [0, 2, 0];
}
}
// 反向添加
let builder = "";
for(let i = len - 1; i >= 0; i--) {
builder += (dictMap[sum[i]);
}
// 以0开头要特判
if(builder.chat(0) == "0"){
builder = builder.substring(1);
}
return builder;
}
```
5. 封装一个EventEmitter类,包括on,emit,off,once.

```javascript
class EventEmitter {
constructor() {
this.handles = {};
}

on(evName, callback){
this.handles[evName] = this.handles[evName] || [];
this.handles[evName].push(callback);
return this;
}

off(evName, callback){
let callbacks = this.handles[evName];
if (callbacks) {]
this.handles[evName = callbacks && callbacks.filter(fn => fn !== callback);
}
return this;
}

trigger(evName, ...args) {
let callbacks = this.handles[evName];
if (callbacks) {
callbacks.forEach(callback => {
callback.call(this, ...args);
})
}
}

once(evName, callback) {
let wrapFunc = (...args) => {
callback.call(this, ...args);
this.off(evName, wrapFunc);
}
this.on(evName, wrapFunc);
}
}
```
6. 手写一个节流函数: throttle

```javascript
function throttle(fn, delay) {
let timer = null;
return function(){
let context = this;
let args = argument;
if(!timer){
setTimeout(() => {
fn.apply(context, args);
timer = null;
}, delay);
}
}
}
```
7. 说一下三栏布局(左定右定中间自适应): 两种方式( flex + (定位+浮动) ) 比较基础。
html搭建结构
```html
<div class="container">
<div class="middle"><h2>中间自适应</h2></div>
<div class="left"><h2>左边栏</h2></div>
<div class="right"><h2>右边栏</h2></div>
</div>
```

```css
.container {
height:200px;
overflow:hidden;
padding: 0 200px;
}
.middle {
width: 100%;
height: 200px;
background-color: deeppink;
float:left;
}
.left {
width: 200px;
height: 200px;
background-color: blue;
float:left;
/* 让左边的盒子上去 需要设置其左边距为负的中间盒子的宽度 */
margin-left: -100%;
position: relative;
left: -200px;
}
.right {
width: 200px;
height: 200px;
background-color: darkorchid;
float:left;
/* 让右边的盒子上去 需要设置其左边距为负的自己的宽度 */
margin-left: -200px;
position: relative;
right: -200px;
}
```

8. 手写一个算法题:给定一个包含非负整数的m * n网格,请找出一条从左上角到右下角的路径,使得路径上的数字总和最小。
(简单的动态规划,代码就不贴了)。

```javascript
// 状态转移方程:
// dp[i][j] = nums[i][j] + Math.min(dp[i-1][j], dp[i][j-1])
```
9. js如何构建二叉树:
参考链接: https://blog.csdn.net/zhenzuo_x/article/details/87968492;
11. 给定一个URL数组,请问js如何实现串行执行[url1, url2, url3,.....]
串行本质上是一个接着一个执行,应该是构建一个promise数组

```javascript
const promise1 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve(5)
},200)
})
const promise2 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve(1)
},300)
})

const promise3 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve(7)
},100)
})
var arr=[promise1,promise2,promise3];
// 第一种方法: async函数
var fn=async function(arr){
for(let i=0,len=arr.length;i<len;i++){
var result=await arr[i]
console.log(result)
}
}
fn(arr)
// Generator
// 这个递归设计的很巧妙
const Cgenerator = function (arr) {
const fn = function* () {
for (let i = 0, len = arr.length; i < len; i++) {
yield arr[i]
}
}
const gen = fn();

const step = function (nextF) {
let next=nextF()
if (next.done) {
return;
}
if (next.value) {
next.value.then((data) => {
console.log(data)
step(() => { return gen.next(); })
})
}
}
step(() => { return gen.next(); })
}
Cgenerator(arr)
// Promise.resolve
// 这个链式调用设计的也相当巧妙: 前一个promsie执行完毕后返回promise赋值给res
const promiseThen=function(arr){
let res=Promise.resolve()
arr.forEach(item => {
res=res.then(()=>{
return item
}).then((data)=>{
console.log(data)
})
});
}
promiseThen(arr)
欢迎关注我的微信工作号:不定期更新前端相关知识,一起学习,共同进步!!!

```

参考文献:
https://blog.csdn.net/qq_39816673/article/details/94209106?ops_request_misc=%25257B%252522request%25255Fid%252522%25253A%252522160976378116780263018323%252522%25252C%252522scm%252522%25253A%25252220140713.130102334..%252522%25257D&request_id=160976378116780263018323&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~sobaiduend~default-3-94209106.first_rank_v2_rank_v29_unweighted&utm_term=promise%E4%B8%B2%E8%A1%8C%E6%89%A7%E8%A1%8C


#字节跳动##校招##前端工程师##面经#
全部评论
这么多手撕代码,感觉好难,是实习岗么?哪个部门呀
点赞 回复
分享
发布于 2021-01-05 10:57
我怎么感觉第6题时防抖啊?
点赞 回复
分享
发布于 2021-01-09 15:24
滴滴
校招火热招聘中
官网直投
楼主promise.all的实现写错了,你这样写不能保证顺序,如果后面的promise先完成,你这样写顺序就会乱
点赞 回复
分享
发布于 2021-01-16 17:49

相关推荐

3 34 评论
分享
牛客网
牛客企业服务