JavaScript est le langage officiel de tous les navigateurs modernes. En conséquence, des questions JavaScript sont posées lors des entretiens avec les développeurs dans différents langages.
Cet article ne couvre pas les dernières bibliothèques JavaScript, les pratiques de développement courantes ou les nouvelles fonctions ES6. Parlons plutôt de 3 questions JavaScript qui reviennent souvent lors des entretiens. J'ai posé ces questions et mes amis ont dit qu'ils les posaient aussi.
Bien sûr, cela ne signifie pas que vous devez apprendre ces 3 questions uniquement lors de la préparation d'un entretien JavaScript - vous avez encore de nombreuses façons de mieux vous préparer pour l'entretien à venir - mais l'intervieweur est très susceptible de réussir les 3 questions suivantes Pour déterminer votre compréhension et votre maîtrise de JavaScript et du DOM.
Commençons ! Notez que nous utilisons du JavaScript natif dans les exemples ci-dessous, car les enquêteurs souhaitent généralement tester votre compréhension de JavaScript et du DOM sans l'aide d'une bibliothèque (par exemple jQuery).
Lors de la création d'une application, vous devez parfois ajouter des écouteurs d'événement aux boutons, au texte ou aux images de la page, et déclencher certaines opérations lorsque l'utilisateur interagit avec ces éléments.
Prenons comme exemple une simple liste de tâches. L'intervieweur vous dira qu'il souhaite déclencher une action lorsque l'utilisateur clique sur un élément de la liste. Et laissez-vous utiliser JavaScript pour implémenter cette fonction selon le code HTML suivant :
<ul id="todo-app"> <li class="item">Walk the dog</li> <li class="item">Pay bills</li> <li class="item">Make dinner</li> <li class="item">Code for one hour</li> </ul>
Vous pouvez ajouter des écouteurs d'événements aux éléments comme le code suivant :
document.addEventListener('DOMContentLoaded', function() { let app = document.getElementById('todo-app'); let items = app.getElementsByClassName('item'); // 给每个列表项添加事件监听器 for (let item of items) { item.addEventListener('click', function() { alert('you clicked on item: ' + item.innerHTML); }); } });
Bien sûr ce qui précède Le code peut répondre aux besoins de l'intervieweur. Le problème est que chaque élément de la liste sera ajouté avec un écouteur d'événement. C'est bien lorsque la liste ne contient que 4 éléments, mais que se passe-t-il si quelqu'un ajoute 10 000 nouveaux éléments à sa liste de tâches (peut-être a-t-il une tonne de choses à faire) ? À ce stade, la fonction créera 10 000 écouteurs d’événements et les ajoutera tous au DOM. Cette efficacité est très faible. Lors de l'entretien, il est préférable de demander d'abord à l'intervieweur combien d'éléments de tâches un utilisateur peut ajouter au maximum. S'il n'y en a jamais plus de 10, le code ci-dessus s'exécutera sans problème. Mais s’il n’y a pas de limite au nombre de tâches qu’un utilisateur peut saisir, vous devez alors trouver une solution plus efficace.
Si l'application dispose de centaines d'écouteurs d'événements, une solution plus efficace consiste à ajouter
unécouteur d'événements au conteneur le plus externe, puis à obtenir l'événement réel lorsque l'utilisateur clique réellement sur le clic pour -faire l'article. C'est ce qu'on appelle un délégué d'événement et c'est plus efficace que d'ajouter des écouteurs d'événement distincts à chaque élément de tâche. Voici le code pour le délégué à l'événement :
Question n°2 : Utiliser les fermetures dans les bouclesdocument.addEventListener('DOMContentLoaded', function() { let app = document.getElementById('todo-app'); // 给容器添加事件监听器 app.addEventListener('click', function(e) { if (e.target && e.target.nodeName === 'LI') { let item = e.target; alert('you clicked on item: ' + item.innerHTML); } }); });
Une fermeture est une
fonction internequi peut accéder à des variables en dehors du champ d'application. Les fermetures peuvent être utilisées pour mettre en œuvre la privatisation et créer des fonctions d’usine. Les questions d'entretien courantes sur les fermetures sont les suivantes : Écrivez une fonction qui boucle sur un
entiertableau et imprime l'index de chaque élément du tableau avec un délai de 3 secondes. L'implémentation courante (incorrecte) de ce problème est la suivante :
Si vous exécutez cette fonction, vous constaterez queconst arr = [10, 12, 15, 21]; for (var i = 0; i < arr.length; i++) { setTimeout(function() { console.log('The index of this number is: ' + i); }, 3000); }
au lieu du attendu 0, 1, 2, 3.
Afin de trouver correctement la raison de cette situation, vous devez comprendre comment JavaScript exécute ce code, et c'est pour cela que l'intervieweur veut vous tester. La raison est que la fonction setTimeout crée une fonction (fermeture) qui accède à la portée externe, qui est la boucle contenant l'index i. Après 3 secondes, la fonction commence à imprimer la valeur de i, et la boucle se termine à ce moment, et la valeur de i est déjà 4. Parce qu'après avoir parcouru 0, 1, 2, 3, 4, il s'arrête finalement à 4. Il existe en fait plusieurs façons de résoudre correctement ce problème. En voici deux :const arr = [10, 12, 15, 21]; for (var i = 0; i < arr.length; i++) { // 给每个函数传入变量 i 让其能访问正确的索引 setTimeout(function(i_local) { return function() { console.log('The index of this number is: ' + i_local); } }(i), 3000); }
const arr = [10, 12, 15, 21]; for (let i = 0; i < arr.length; i++) { // 使用 ES6 中的 let 关键字,它会在函数调用时创建一个新的绑定 // 了解更多:http://exploringjs.com/es6/ch_variables.html#sec_let-const-loop-heads setTimeout(function() { console.log('The index of this number is: ' + i); }, 3000); }
Debouncing 是解决这个问题的一种方法,它的做法是限制下次函数调用之前必须等待的时间间隔。正确实现 debouncing 的方法是将若干个函数调用 合成 一次,并在给定时间过去之后仅被调用一次。下面是一个原生 JavaScript 的实现,用到了 作用域 , 闭包, this , 和 计时事件 :
// 将会包装事件的 debounce 函数 function debounce(fn, delay) { // 维护一个 timer let timer = null; // 能访问 timer 的闭包 return function() { // 通过 ‘this’ 和 ‘arguments’ 获取函数的作用域和变量 let context = this; let args = arguments; // 如果事件被调用,清除 timer 然后重新设置 timer clearTimeout(timer); timer = setTimeout(function() { fn.apply(context, args); }, delay); } }
这个函数 — 当传入一个事件(fn)时 — 会在经过给定的时间(delay)后执行。
函数这样用:
// 当用户滚动时被调用的函数 function foo() { console.log('You are scrolling!'); } // 在 debounce 中包装我们的函数,过 2 秒触发一次 let elem = document.getElementById('container'); elem.addEventListener('scroll', debounce(foo, 2000));
Throttling 是与 debouncing 类似的一种技术,但它不是在调用函数之前等待一段时间,throttling 是在较长的时间间隔内调用函数。所以如果一个事件每 100 毫秒被触发 10 次,throttling 会在每隔 2 秒时执行一次这个函数,而不是在 100 毫秒内执行 10 次事件。
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!