这是前端社招面试总结的第二篇编程篇,没看过第一篇算法篇的可以看一下。
前言
前端社招面试,考工程编程题的比例要比纯算法要高。因为编程题中很多问题是实际工作中经常会遇到的,可以实际考察对javascript知识的理解和掌握程度。
面试过程中遇到的编程题
科里化
- 自定义加法,a, b 两数相加,a、b 有可能是浮点数
1 | function add(a, b) { |
小tip:面试官可能会问的问题,0.1+0.2===0.3吗,为什么
- 优化上面的函数,实现add(0.1)(0.2)(0.3)() === 0.6
1 | function superAdd(a, b) { |
- 继续优化以上函数,实现add(0.1)(0.2)(0.3) === 0.6
1 | function superAdd(a, b) { |
- 继续优化以上函数,实现不限定参数个数,比如add(0.1, 0.2, 0.3)(0.4) = 1
1 | function superAdd(a, b) { |
实现LazyMan
1 | 实现一个LazyMan,可以按照以下方式调用: |
function的方式
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
39
40
41
42
43function LazyMan(name) {
var task = () => { console.log(name); next() };
var tasks = [task];
var next = () => {
if (tasks.length) {
var tt = tasks.shift();
tt && tt();
}
}
var res = {
eat: function (type) {
tasks.push(() => {
console.log(type);
next();
});
return res;
},
sleep: function (time) {
var task = () => {
setTimeout(() => {
console.log(`sleep ${time}`);
next();
}, time)
}
tasks.push(task);
return res;
},
sleepFirst: function (time) {
var task = () => {
setTimeout(() => {
console.log(`sleep ${time}`);
next();
}, time)
}
tasks.unshift(task);
return res;
}
}
setTimeout(() => { next() });
return res;
}
LazyMan('Tony').eat('lunch').sleep(10).eat('dinner').sleepFirst(5000);
}class的方式
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
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53class LazyManClass {
// 构造函数
constructor(name) {
this.name = name
// 定义一个数组存放执行队列
this.queue = [()=>{
console.log(`Hi I am ${name}`)
this.next()
}]
setTimeout(() => {
this.next()
}, 0)
}
// 定义原型方法
eat(food) {
var fn = () => {
console.log(`I am eating ${food}`)
this.next()
}
this.queue.push(fn)
return this
}
sleep(time) {
var fn = () => {
// 等待了10秒...
setTimeout(() => {
console.log(`等待了${time}秒`)
this.next()
}, 1000 * time)
}
this.queue.push(fn)
return this
}
sleepFirst(time) {
var fn = () => {
// 等待了5秒...
setTimeout(() => {
console.log(`等待了${time}秒`)
this.next()
}, 1000 * time)
}
this.queue.unshift(fn)
return this
}
next() {
var fn = this.queue.shift()
fn && fn()
}
}
function LazyMan(name) {
return new LazyManClass(name)
}
LazyMan('Tony').eat('lunch').eat('dinner').sleepFirst(5).sleep(10).eat('junk food')
手写系列
- 实现一个 EventEmitter 类,作用是进行事件的监听和触发
1 | class EventEmitter { |
- 实现一个 iterate 方法,作用是按照字典序遍历对象
1 | - @param {object} obj 传入的对象 |
- 实现深拷贝
- 手写继承
- 手写Promise、Promise.all、Promise.race、Promise.finally
- 实现Array.isArray
- 实现Array.reduce()
- 模拟new操作
- 其他手写操作可参考(https://juejin.cn/post/6875152247714480136)
网络类
实现ajax函数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20// promise版
function myAjax(url) {
return new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest()
// 知识点:xhr.open(method, url, async, username, password);第三个参数请求方式是否为异步,默认为true
xhr.open('GET', url)
xhr.onreadystatechange = function () {
// 知识点:readyState 0尚未调用xhr.open 1已调用xhr.open 2已调用xhr.send 3下载中 4下载已完成
if (this.readyState === 4) {
if (this.status === 200 || this.status === 304) {
resolve(this.response)
} else {
reject(new Error(this.statusText))
}
}
}
// 知识点:send(body),body-post请求的数据体
xhr.send()
})
}实现带超时功能的ajax,超过time时间请求未完成时,取消请求
1 | function myAjax(url, timeout) { |
- 实现一个异步请求管理方法。有 200 个异步请求要发送出去,但是同时最多只能发送 5 个请求。如何能够最快请求完全部请求。
- 手写jsonp
dom类
- 获取页面中出现次数最多的节点