Maison > interface Web > js tutoriel > 3 questions d'entretien JavaScript auxquelles prêter attention

3 questions d'entretien JavaScript auxquelles prêter attention

怪我咯
Libérer: 2017-04-05 14:00:39
original
1303 Les gens l'ont consulté

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).

Question n°1 : Proxy d'événement

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>
Copier après la connexion

Vous pouvez ajouter des écouteurs d'événements aux éléments comme le code suivant :

document.addEventListener(&#39;DOMContentLoaded&#39;, function() {

  let app = document.getElementById(&#39;todo-app&#39;);
  let items = app.getElementsByClassName(&#39;item&#39;);

  // 给每个列表项添加事件监听器
  for (let item of items) {
    item.addEventListener(&#39;click&#39;, function() {
      alert(&#39;you clicked on item: &#39; + item.innerHTML);
    });
  }

});
Copier après la connexion

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 boucles
document.addEventListener(&#39;DOMContentLoaded&#39;, function() {

  let app = document.getElementById(&#39;todo-app&#39;);

  // 给容器添加事件监听器
  app.addEventListener(&#39;click&#39;, function(e) {
    if (e.target && e.target.nodeName === &#39;LI&#39;) {
      let item = e.target;
      alert(&#39;you clicked on item: &#39; + item.innerHTML);
    }
  });

});
Copier après la connexion

Les fermetures sont souvent demandées lors des entretiens car l'intervieweur peut utiliser votre répondez à cette question pour évaluer votre familiarité avec la langue et voir si vous savez quand utiliser les fermetures.

Une fermeture est une

fonction interne

qui 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

entier

tableau 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 que
const arr = [10, 12, 15, 21];
for (var i = 0; i < arr.length; i++) {
  setTimeout(function() {
    console.log(&#39;The index of this number is: &#39; + i);
  }, 3000);
}
Copier après la connexion
4 est imprimé à chaque fois après 3 secondes.

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(&#39;The index of this number is: &#39; + i_local);
    }
  }(i), 3000);
}
Copier après la connexion
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(&#39;The index of this number is: &#39; + i);
  }, 3000);
}
Copier après la connexion
Problème n°3 : Anti-rebond

Certains événements du navigateur peuvent être déclenchés plusieurs fois sur une courte période de temps, comme redimensionner la fenêtre ou faire défiler la page. Si vous ajoutez un écouteur d'événement à l'événement de défilement de la fenêtre et que l'utilisateur continue de faire défiler la page rapidement, votre événement peut être déclenché des milliers de fois en 3 secondes. Cela peut entraîner des problèmes de performances très graves.

Si l'entretien traite de la création d'applications et d'événements de défilement, d'événements de redimensionnement de fenêtre ou d'événements de clavier, etc., assurez-vous de mentionner l'anti-rebond ou la limitation comme moyen d'améliorer la vitesse et les performances des pages. Prenons un exemple d'astuces CSS :

En 2011, Twitter avait un problème : lors du défilement du résumé Twitter, la page devenait très bloquée, voire ne répondait plus. John Resig a écrit un blog sur ce problème, expliquant pourquoi lier des fonctions chronophages directement à l'événement de défilement est une mauvaise idée.

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);
  }
}
Copier après la connexion

这个函数 — 当传入一个事件(fn)时 — 会在经过给定的时间(delay)后执行。

函数这样用:

// 当用户滚动时被调用的函数
function foo() {
  console.log(&#39;You are scrolling!&#39;);
}

// 在 debounce 中包装我们的函数,过 2 秒触发一次
let elem = document.getElementById(&#39;container&#39;);
elem.addEventListener(&#39;scroll&#39;, debounce(foo, 2000));
Copier après la connexion

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!

Étiquettes associées:
source:php.cn
Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal