前端中级工程师 - 手写编程题
题目一
描述: 编写一个 People
类,使其的实例具有监听事件、触发事件、解除绑定功能。(实例可能监听多个不同的事件,也可以去除监听事件)
class People {
constructor(name) {
this.name = name
}
sayHi() {
console.log(`Hi, I am ${this.name}`)
}
}
const say1 = greeting => {
console.log(`${greeting}, nice meeting you.`)
}
const say2 = greeting => {
console.log(`${greeting}, nice meeting you, too.`)
}
const jerry = new People('Jerry')
jerry.sayHi()
jerry.on('greeting', say1)
jerry.on('greeting', say2)
jerry.emit('greeting', 'Hi')
jerry.off('greeting', say1)
jerry.emit('greeting', 'Hi')
分析: 这道题主要靠面向对象的知识,事件监听与销毁
实现方案:
class People {
constructor(name) {
this.name = name
}
evtLoop = []
on(evtType, func) {
this.validate(func)
this.evtLoop.push({ evtType, func })
}
emit(eventType, options) {
this.evtLoop
.filter(({ evtType }) => eventType === evtType)
.forEach(item => item.func(options))
}
off(evtType, func) {
this.validate(func)
const idx = this.evtLoop.findIndex(item => item.evtType === evtType && item.func === func)
idx < 0 && this.evtLoop.splice(idx, 1)
}
validate(func) {
if (typeof func !== 'function') {
throw new Error('监听事件必须是一个函数,请重新输入')
}
}
sayHi() {
console.log(`Hi, I am ${this.name}`)
}
}
题目二
描述: 完成 sleep
函数,可以达到下面的效果
const sleep = duration => {
}
const anyFunc = async () => {
console.log('123')
await sleep(300)
console.log('456')
}
分析: 这题主要考查 js 的事件机制
实现方案: (这题有多种实现方案)
const sleep = duration => {
return new Promise(resolve => setTimeout(resolve, duration))
}
题目三
描述: 完成 deepGet
函数,给它传入一个对象和字符串,字符串表示对象深层属性的获取路径,可以深层次获取对象内容
const deepGet = (obj, prop) => {
}
deepGet(
{
school: {
student: { name: 'Tomy' }
}
},
'school.student.name'
)
deepGet(
{
school: {
students: [{ name: 'Tomy' }, { name: 'Lucy' }]
}
},
'school.students[1].name'
)
deepGet({ user: { name: 'Tomy' } }, 'user.age')
deepGet({ user: { name: 'Tomy' } }, 'school.user.age')
分析: 这题考察对数组以及对象方法的使用
实现方案:
const deepGet = (obj, prop) => {
const keyArr = prop.split('.').map(item => item)
const reducer = (acc, cur) => {
const objKey = cur.includes('[') && cur.replaceAll(/[\[?=0-9\]$]/gi, '')
if (Array.isArray(acc[objKey])) {
cur = cur.replaceAll(/[^?=0-9]/gi, '')
return acc[objKey][cur] || {}
}
return acc[cur] ? acc[cur] : {}
}
const result = keyArr.reduce(reducer, obj)
return Object.keys(result).length ? result : undefined
}
题目四
描述: 完成 combo
函数,它接受任意多个单参函数(只接受一个参数的函数)作为参数,并且返回一个函数,它的作用:使得类似 f(g(h(a)))
这样的函数调用可以简写为 combo(f, g, h)(a)
const combo = () => {
}
const addOne = a => a + 1
const multiTwo = a => a * 2
const divThree = a => a / 3
const toString = a => a + ''
const split = a => a.split('')
split(toString(addOne(multiTwo(divThree(666)))))
const testForCombo = combo(split, toString, addOne, multiTwo, divThree)
testForCombo(666)
分析: 这道题主要考察高阶函数 - 柯里化函数的使用
实现方案:
const combo = (...funcs) => {
funcs.length && funcs.reverse()
return prop =>
funcs.reduce((acc, cur) => {
return cur(acc)
}, prop)
}
题目五
描述: 有两个盘子分别放有 5 个和 7 个小球,两个朋友玩游戏:每个人轮流从两个盘子中拿小球,每人每次只能从其中一个盘子中拿,每次可以拿 1 个或者多个(不能一个都不拿),拿到最后一个小球的人算输,问开局先手和后手是否有必胜策略?如果有,请描述必胜策略。
分析: 这考题主要考察算法能力
实现方案: 假设: 1 号盘子: 5 个球, 2 号盘子 7 个球, 一个小朋友名为小 A,另一名为小 B
-
小 A 先手: 先拿 2 号盘子的 2 个小球,只要先手的一方尽量保证两个盘子的数量相同的就行,直至决胜轮
-
小 A 后手:暂未想到