Google 的 JavaScript 面试题
大家好,欢迎回到“代码评审”系列,这是一个每周在 Dev.to 独家发布的编程面试挑战和职业相关内容系列。我叫伊丽莎白,从事软件工程师工作已有 4 年多了。我热衷于分享我的知识,以及在面试中脱颖而出或提升编程技能的最佳技巧和窍门。如果您想获得更多类似的内容和挑战,请点击此处订阅 Coderbyte 时事通讯。单口相声系列就到这里——让我们开始挑战吧!
挑战
编写一个类,EventEmitter
它有三个方法:on
、、emit
和removeListener
。
on("eventName", callbackFn)
- 一个接受eventName
和 的函数,应该保存在发出callbackFn
事件时要调用的callbackFn 。eventName
emit("eventName", data)
- 一个接受eventName
和data
对象的函数,应该调用callbackFn
与该事件关联的 s 并向它们传递data
对象。removeListener("eventName", callbackFn)
- 一个接受eventName
和的函数,应该从事件中callbackFn
删除它。callbackFn
例如:
let superbowl = new EventEmitter()
const cheer = function (eventData) {
console.log('RAAAAAHHHH!!!! Go ' + eventData.scoringTeam)
}
const jeer = function (eventData) {
console.log('BOOOOOO ' + eventData.scoringTeam)
}
superbowl.on('touchdown', cheer)
superbowl.on('touchdown', jeer)
superbowl.emit('touchdown', { scoringTeam: 'Patriots' }) // Both cheer and jeer should have been called with data
superbowl.removeListener('touchdown', jeer)
superbowl.emit('touchdown', { scoringTeam: 'Seahawks' }); // Only cheer should have been called
解决方案:
这是使用 ES6 类的绝佳机会。如果您以前没用过,可以在这里查看它们的语法。我们可以从类的基本结构开始,并用一个用于跟踪事件的EventEmitter
对象来初始化它。events
class EventEmitter {
constructor () {
this.events = {}
}
}
在
接下来我们可以开始编写方法了。首先是on
。代码如下:
on (eventName, callbackFn) {
if (!this.events[eventName]) {
this.events[eventName] = []
}
this.events[eventName].push(callbackFn)
}
因为函数是JavaScript 中的第一类对象eventName
,这基本上意味着它们可以存储在变量、对象或数组中,所以我们可以将回调函数推送到存储在事件对象中的键的数组中。
发射
现在,开始我们的emit
功能。
emit (eventName, eventData) {
if (!this.events[eventName]) return
this.events[eventName].forEach(fn => fn(eventData))
}
此解决方案利用了 JavaScript 中所谓的“闭包”。如果你在面试中使用 JavaScript 编写代码,理解闭包至关重要。闭包的本质是函数引用了其周围的状态或词法环境。你也可以将其理解为一个允许你在内部函数中访问外部函数作用域的闭包。使用全局变量就是一个很棒的闭包简单示例。
这是使用闭包来跟踪函数被调用次数的另一个很好的例子。
function tracker (fn) {
let numTimesCalled = 0
return function () {
numTimesCalled++
console.log('I was called', numTimesCalled)
return fn()
}
}
function hello () {
console.log('hello')
}
const trackedHello = tracker(hello)
返回的内部函数tracker
覆盖了变量 numTimesCalled,并在trackedHello
函数的整个生命周期内保持对它的引用。很酷吧?
删除监听器
这种removeListener
方法可能是三种方法中最简单的。这里有一个解决方案:
removeListener (eventName, callbackFn) {
const idx = this.events[eventName].indexOf(callbackFn)
if (idx === -1) return
this.events[eventName].splice(idx, 1)
}
课程就到这里!双关语:)看看自己能否实现语言本身的方法是备战面试的好方法。下周见!
文章来源:https://dev.to/coderbyte/a-javascript-interview-question-asked-at-google-19f1