Heim > Artikel > Web-Frontend > JS-Interviewfragen, bei denen mehr als 80 % der Befragten durchfallen
Insgesamt 5024 Wörter. Das Lesen dauert 6 Minuten und das schnelle Lesen dieses Artikels wurde erstmals wöchentlich in der Zhihu-Kolumne veröffentlicht. Wie bereits geschrieben, hat der Autor in mehr als zwei Jahren als Interviewer Hunderte von Front-End-Ingenieuren interviewt. Ich war überrascht, dass mehr als 80 % der Kandidaten die Antwort auf die folgende Frage nicht einmal bestanden haben. Was ist das für eine magische Interviewfrage? Welche Fähigkeiten prüft er bei Kandidaten? Welche Auswirkungen hat es für Sie, die Sie diesen Artikel lesen? Lassen Sie es mich Ihnen langsam sagen (relevante Empfehlung „Front-End-Interviewfragen“)
Rekrutierung von Front-End-Ingenieuren, insbesondere im mittleren bis mittleren Für erfahrene Front-End-Ingenieure ist eine solide JS-Grundlage unbedingt erforderlich. Ingenieure mit einer schwachen Grundlage werden bei verschiedenen Problemen in der Front-End-Entwicklung höchstwahrscheinlich hilflos sein. Wenn ich die JS-Grundlage des Kandidaten untersuche, stelle ich oft den folgenden Code zur Verfügung und bitte den Kandidaten dann, die Ergebnisse seiner tatsächlichen Operation zu analysieren:
for (var i = 0; i < 5; i++) {
setTimeout(function() {
console.log(new Date, i);
}, 1000);
}
console.log(new Date, i);
Dieser Code ist sehr kurz, nur 7 Zeilen, denke ich Schüler, die dies lesen, brauchen wahrscheinlich nicht, dass ich Zeile für Zeile erkläre, was dieser Code macht. Auch die Ergebnisse, die Kandidaten mit diesem Code geben, sind unterschiedlich:
0,1,2,3,4,5
; 5,0,1,2,3,4
5,5,5,5,5,5
2017-03-18T00:43:45.873Z 5
2017-03-18T00:43:46.866Z 5
2017-03-18T00:43:46.868Z 5
2017-03-18T00:43:46.868Z 5
2017-03-18T00:43:46.868Z 5
2017-03-18T00:43:46.868Z 5
Als nächstes frage ich: Wenn wir uns einig sind, verwenden Sie einen Pfeil, um ein Zeitintervall von 1 Sekunde zwischen den beiden anzuzeigen Ausgaben davor und danach, und ein Komma, um die beiden Ausgaben davor und danach anzugeben. Das Zeitintervall zwischen ihnen kann ignoriert werden. Wie kann man die tatsächlichen Ergebnisse der Ausführung des Codes beschreiben? Es gibt die folgenden zwei Antworten: 5 -> 5 -> 5 -> 5 -> 5, das heißt, die ersten 5 werden direkt ausgegeben und nach 1 Sekunde werden 5 5 ausgegeben </pre>
<li>
<code class="code">5 -> 5,5,5,5,5
Dies erfordert, dass die Kandidaten verstehen Das Timing in JS ist sehr vertraut. Während der Ausführung der Schleife werden 5 Timer fast gleichzeitig eingestellt. Unter normalen Umständen werden diese Timer nach 1 Sekunde ausgelöst und die Ausgabe erfolgt sofort . Offensichtlich ist die richtige Beschreibung B. for (var i = 0; i < 5; i++) {
(function(j) { // j = i
setTimeout(function() {
console.log(new Date, j);
}, 1000);
})(i);
}console.log(new Date, i);
Verwenden Sie IIFE (Immediately Invoked Function Expression: ein Funktionsausdruck, der deklariert und ausgeführt wird), um die durch Abschlüsse verursachten Probleme zu lösen In der Tat eine gute Idee, aber Anfänger finden solchen Code möglicherweise nicht leicht zu verstehen. Zumindest als ich anfing, habe ich eine Weile darüber nachgedacht, bevor ich ihn wirklich verstanden habe. 5 -> 0,1,2,3,4Gibt es einen intuitiveren Ansatz? Die Antwort lautet: Ja, wir müssen lediglich einige Anpassungen am Schleifenkörper vornehmen, damit der für die Ausgabe verantwortliche Code den i-Wert jeder Schleife erhalten kann. Was zu tun? Unter Ausnutzung der Funktion, dass die Parameterübergabe des primitiven Typs in JS die Übergabe nach Wert ist, ist es nicht schwierig, den folgenden Code umzuwandeln:
var output = function (i) {
setTimeout(function() {
console.log(new Date, i);
}, 1000);
};
for (var i = 0; i < 5; i++) {
output(i); // 这里传过去的 i 值被复制了
}
console.log(new Date, i);
for (let i = 0; i < 5; i++) {
setTimeout(function() {
console.log(new Date, i);
}, 1000);
}
console.log(new Date, i);
Aufmerksame Schüler werden feststellen, dass es hier nur eine sehr subtile Änderung gibt, nämlich die Verwendung von let in ES6-Blockbereich (Block Scope). . var wird verwendet, aber der Code meldet einen Fehler, wenn er tatsächlich ausgeführt wird, da das in der letzten Ausgabe verwendete i nicht in dem Bereich vorhanden ist, in dem es sich befindet, und i nur innerhalb der Schleife existiert. Schüler, denen ES6-Funktionen einfallen, antworten möglicherweise nicht richtig, haben aber gezeigt, dass sie ES6 verstehen. Sie können 5 Punkte hinzufügen und die folgenden Fragen fortsetzen. Folgefrage 2: ES6Erfahrene Front-End-Studenten sind möglicherweise etwas ungeduldig, nachdem sie dies gelesen haben. Keine Sorge, die Schwierigkeit Die Herausforderung wird weiter zunehmen. 接着上文继续追问:如果期望代码的输出变成 看到这里,部分同学会给出下面的可行解: 不得不承认,这种做法虽粗暴有效,但是不算是能额外加分的方案。如果把这次的需求抽象为:在系列异步操作完成(每次循环都产生了 1 个异步操作)之后,再做其他的事情,代码该怎么组织?聪明的你是不是想起了什么?对,就是 Promise。 可能有的同学会问,不就是在控制台输出几个数字么?至于这样杀鸡用牛刀?你要知道,面试官真正想考察的是候选人是否具备某种能力和素质,因为在现代的前端开发中,处理异步的代码随处可见,熟悉和掌握异步操作的流程控制是成为合格开发者的基本功。 顺着下来,不难给出基于 Promise 的解决方案(既然 Promise 是 ES6 中的新特性,我们的新代码使用 ES6 编写是不是会更好?如果你这么写了,大概率会让面试官心生好感): 相比而言,笔者更倾向于下面这样看起来更简洁的代码,要知道编程风格也是很多面试官重点考察的点,代码阅读时的颗粒度更小,模块化更好,无疑会是加分点。 读到这里的同学,恭喜你,你下次面试遇到类似的问题,至少能拿到 80 分。 我们都知道使用 Promise 处理异步代码比回调机制让代码可读性更高,但是使用 Promise 的问题也很明显,即如果没有处理 Promise 的 reject,会导致错误被丢进黑洞,好在新版的 Chrome 和 Node 7.x 能对未处理的异常给出 Unhandled Rejection Warning,而排查这些错误还需要一些特别的技巧(浏览器、Node.js)。 既然你都看到这里了,那就再坚持 2 分钟,接下来的内容会让你明白你的坚持是值得的。 多数面试官在决定聘用某个候选人之前还需要考察另外一项重要能力,即技术自驱力,直白的说就是候选人像有内部的马达在驱动他,用漂亮的方式解决工程领域的问题,不断的跟随业务和技术变得越来越牛逼,究竟什么是牛逼?建议阅读程序人生的这篇剖析。 回到正题,既然 Promise 已经被拿下,如何使用 ES7 中的 async await 特性来让这段代码变的更简洁?你是否能够根据自己目前掌握的知识给出答案?请在这里暂停 1 分钟,思考下。 下面是笔者给出的参考代码: 感谢你花时间读到这里,相信你收获的不仅仅是用 JS 精确控制代码输出的各种技巧,更是对于前端工程师的成长期许:扎实的语言基础、与时俱进的能力、强大技术自驱力。 推荐教程:《JS教程》 Das obige ist der detaillierte Inhalt vonJS-Interviewfragen, bei denen mehr als 80 % der Befragten durchfallen. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!0 -> 1 -> 2 -> 3 -> 4 -> 5,并且要求原有的代码块中的循环和两处 console.log 不变,该怎么改造代码?新的需求可以精确的描述为:代码执行时,立即输出 0,之后每隔 1 秒依次输出 1,2,3,4,循环结束后在大概第 5 秒的时候输出 5(这里使用大概,是为了避免钻牛角尖的同学陷进去,因为 JS 中的定时器触发时机有可能是不确定的,具体可参见 How Javascript Timers Work)。
for (var i = 0; i < 5; i++) {
(function(j) {
setTimeout(function() {
console.log(new Date, j);
}, 1000 * j); // 这里修改 0~4 的定时器时间
})(i);
}
setTimeout(function() {
// 这里增加定时器,超时设置为 5 秒
console.log(new Date, i);
}, 1000 * i);
const tasks = [];
for (var i = 0; i < 5; i++) { // 这里 i 的声明不能改成 let,如果要改该怎么做?
((j) => {
tasks.push(new Promise((resolve) => {
setTimeout(() => {
console.log(new Date, j);
resolve(); // 这里一定要 resolve,否则代码不会按预期 work
}, 1000 * j); // 定时器的超时时间逐步增加
}));
})(i);
}
Promise.all(tasks).then(() => {
setTimeout(() => {
console.log(new Date, i);
}, 1000); // 注意这里只需要把超时设置为 1 秒
});
const tasks = []; // 这里存放异步操作的 Promise
const output = (i) => new Promise((resolve) => {
setTimeout(() => {
console.log(new Date, i);
resolve();
}, 1000 * i);
});
// 生成全部的异步操作
for (var i = 0; i < 5; i++) {
tasks.push(output(i));
}
// 异步操作完成之后,输出最后的 i
Promise.all(tasks).then(() => {
setTimeout(() => {
console.log(new Date, i);
}, 1000);
});
追问 3:ES7
// 模拟其他语言中的 sleep,实际上可以是任何异步操作
const sleep = (timeountMS) => new Promise((resolve) => {
setTimeout(resolve, timeountMS);
});
(async () => { // 声明即执行的 async 函数表达式
for (var i = 0; i < 5; i++) {
await sleep(1000);
console.log(new Date, i);
}
await sleep(1000);
console.log(new Date, i);
})();
总结