fe-learning
fe-learning copied to clipboard
记一次字节前端笔试
字节跳动前端面经
其他与个人项目相关的就不说了,直接来看笔试题。
题目
看代码写输出
var result = [];
var a = 3;
var total = 0;
function foo(a) {
var i = 0;
// 注意这里的i后置加
for (; i < 3; i++) {
result[i] = function() {
total += i * a;
console.log(total);
}
}
}
foo(1);
result[0](); // 3
result[1](); // 6
result[2](); // 9
-
如果将
var i = 0改为let, 输出是否会变化不会,这里
i是定义在foo函数作用域内的。
注解:
用闭包来解释这题会更好,因为i是定义在foo函数作用域里的,result数组里的函数运行时相当于从foo函数作用域外引用i、a变量,这个时候foo循环已经退出了,i因为后置加的存在在退出循环以后等于3,a因为参数传入为1,所以输出就是3、6、9。如果这里参数不指定a的话,就会直接沿着作用域链往上查找到定义在全局作用域的a = 3,最后结果为9、18、27。如果foo不传入参数,a还是在foo函数作用域,相当于写了一条 var a; // undefined,最后输出三个NaN。
二进制加法
实现一个二进制加法,输入输出均为二进制字符串
function binaryAdd(num1: string, num2: string): string {
// TODO
}
//Example
binaryAdd('1010', '111') // '10001'
leetcode原题,二进制求和
和链表求和、字符串加法差不多,进位进入第二次运算即可,计算完成如进位有余记得补位
function addBinary(a,b) {
let ans = '', carry = 0
let pa = a.length-1;
let pb = b.length-1;
while (pa >=0 || pb >= 0) {
const sum = Number(a[pa] || 0) + Number(b[pb] || 0) + carry
carry = Math.floor(sum / 2);
ans = sum % 2 + ans
pa--;
pb--;
}
if(carry !== 0) ans = '1' + ans
return ans
}
实现一个带并发限制的异步队列
实现一个带并发限制的异步调度器Scheduler,保证同时运行的任务最多有两个。完善代码中Scheduler类,使得以下程序能正确输出
class Scheduler {
add(promiseCreator) {
// TODO
}
// TODO
}
const timeout = (time) => new Promise(resolve => {
setTimeout(resolve, time)
})
const scheduler = new Scheduler();
const addTask = (time, order) => {
scheduler.add(() => timeout(time))
.then(() => console.log(order))
}
addTask(1000, '1')
addTask(500, '2')
addTask(300, '3')
addTask(400, '4')
// output: 2 3 1 4
// 一开始,1、2两个任务进入队列
// 500ms时,2完成,输出2,任务3进队
// 800ms时,3完成,输出3,任务4进队
// 1000ms时,1完成,输出1
// 1200ms时,4完成,输出4
// 实现如下
class Scheduler {
constructor () {
this.tasks = [] // 任务缓冲队列
this.runningTask = [] // 任务队列
}
// promiseCreator 是一个异步函数,return Promise
add (promiseCreator) {
return new Promise((resolve, reject) => {
promiseCreator.resolve = resolve
if (this.runningTask.length < 2) {
this.run(promiseCreator)
} else {
this.tasks.push(promiseCreator)
}
})
}
run (promiseCreator) {
this.runningTask.push(promiseCreator)
promiseCreator().then(() => {
promiseCreator.resolve()
// 删除运行完的任务
this.runningTask.splice(this.runningTask.findIndex(promiseCreator), 1)
if (this.tasks.length > 0) {
this.run(this.tasks.shift())
}
})
}
}
小结
字节还是很考基础,面了两次下来感觉最大的问题就是这块,平时实践较多但是深度不够,比如第三题那个带并发限制的异步队列,读完题后没有较好的思路。
如果单纯从准备面试的角度,除开基础知识预备,算法题这些,JS这块可以关注一下事件循环、作用域、原型链继承,再就是各种花式异步操作等等。