Maison  >  Article  >  interface Web  >  7 questions d'entretien sur les fermetures en JavaScript, pouvez-vous y répondre ?

7 questions d'entretien sur les fermetures en JavaScript, pouvez-vous y répondre ?

青灯夜游
青灯夜游avant
2021-03-26 09:41:575930parcourir

7 questions d'entretien sur les fermetures en JavaScript, pouvez-vous y répondre ?

Recommandations associées : Résumé des questions d'entretien Big Front-End 2021 (Collection)

Chaque programmeur JavaScript doit savoir quoi une fermeture est. Lors d'un entretien JavaScript, vous serez très probablement interrogé sur le concept de fermetures.

Voici 7 questions d'entretien difficiles sur les fermetures JavaScript.

Ne regardez pas les réponses et n'exécutez pas le code pour voir à quel point vous êtes bon. Il faut environ une demi-heure pour répondre à ces questions.

1. La gamme

possède les fonctions suivantes clickHandler, immediate et delayedReload :

let countClicks = 0;
button.addEventListener('click', function clickHandler() {
  countClicks++;
});
const result = (function immediate(number) {
  const message = `number is: ${number}`;
  return message;
})(100);
setTimeout(function delayedReload() {
  location.reload();
}, 1000);

Laquelle de ces 3 fonctions peut-on accéder aux variables de portée externe ?

Réponse

  • clickHandler Possibilité d'accéder aux variables countClicks depuis une portée externe.

  • immediate ne peut accéder à aucune variable dans la portée externe.

  • delayedReload Accédez aux variables globales location à partir de la portée globale (c'est-à-dire la portée la plus externe).

Tutoriels associés recommandés : Tutoriel vidéo javascript

Paramètres perdus

Le code suivant. Qu'est-ce que le résultat :

(function immediateA(a) {
  return (function immediateB(b) {
    console.log(a); // => ?
  })(1);
})(0);

Réponse

Le résultat est : 0

Appel 0 avec le paramètre immediateA, donc a paramètre pour 0. La fonction

immediateB, imbriquée dans la fonction immediateA, est une fermeture qui obtient la variable immediateA de la portée a externe, où a est 0. La sortie de console.log(a) est donc 0.

3. Qui est qui

Que produira le code suivant ?

let count = 0;
(function immediate() {
  if (count === 0) {
    let count = 1;
    console.log(count); // 输出什么?
  }
  console.log(count); // 输出什么?
})();

Réponse

sorties 1 et 0

La première instruction let count = 0 déclare une variable count.

immediate() est une fermeture qui récupère la variable count de la portée externe. Dans la portée de la fonction immediate(), count est 0.

Cependant, dans la condition, un autre let count = 1 déclare une variable locale count qui remplace le count en dehors de la portée. Les premières console.log(count) sorties 1.

Le deuxième console.log(count) est affiché sous la forme 0 car la variable count ici est accessible depuis la portée externe.

4. Fermetures délicates

Que produit le code suivant :

for (var i = 0; i < 3; i++) {
  setTimeout(function log() {
    console.log(i); // => ?
  }, 1000);
}

Réponse

Sortie : 3, 3, 3.

Le code est exécuté en deux étapes.

Phase 1

  1. for() Répétez 3 fois. Sur chaque boucle une nouvelle fonction log() est créée qui capture la variable i. setTimout() planifie log() pour s'exécuter après 1000 millisecondes.
  2. Lorsque la boucle for() se termine, la variable i a la valeur 3.

Phase 2

La deuxième phase se produit après 1000 ms :

  1. setTimeout() Exécuter la fonction log() programmée. log() lit la valeur actuelle de la variable i 3 et génère 3

donc affiche 3, 3, 3.

5. Message d'erreur

Qu'est-ce que le code suivant affichera :

function createIncrement() {
  let count = 0;
  function increment() { 
    count++;
  }

  let message = `Count is ${count}`;
  function log() {
    console.log(message);
  }
  
  return [increment, log];
}

const [increment, log] = createIncrement();
increment(); 
increment(); 
increment(); 
log(); // => ?

Réponse

Sortie : 'Count is 0'

increment() La fonction est appelée 3 fois, augmentant de count à 3. Les variables

message existent dans le cadre de la fonction createIncrement(). Sa valeur initiale est 'Count is 0'. Mais même si la variable count a été incrémentée plusieurs fois, la valeur de la variable message est toujours 'Count is 0'. La fonction

log() est une fermeture qui prend la variable createIncrement() de la portée message. console.log(message) La sortie est enregistrée 'Count is 0' sur la console.

6. Repackage

La fonction suivante createStack() est utilisée pour créer la structure de pile :

function createStack() {
  return {
    items: [],
    push(item) {
      this.items.push(item);
    },
    pop() {
      return this.items.pop();
    }
  };
}

const stack = createStack();
stack.push(10);
stack.push(5);
stack.pop(); // => 5

stack.items; // => [10]
stack.items = [10, 100, 1000]; // 栈结构的封装被破坏了

Cela fonctionne bien, mais il y a un small Le problème est que, comme l'attribut stack.items est exposé, n'importe qui peut modifier directement le tableau items.

C'est un gros problème car cela casse l'encapsulation de la pile : seules les méthodes push() et pop() doivent être publiques, et ni stack.items ni aucun autre détail ne doit être accessible.

使用闭包的概念重构上面的栈实现,这样就无法在 createStack() 函数作用域之外访问 items 数组:

function createStack() {
  // 把你的代码写在这里
}

const stack = createStack();
stack.push(10);
stack.push(5);
stack.pop(); // => 5

stack.items; // => undefined

答案

以下是对 createStack() 的重构:

function createStack() {
  const items = [];
  return {
    push(item) {
      items.push(item);
    },
    pop() {
      return items.pop();
    }
  };
}

const stack = createStack();
stack.push(10);
stack.push(5);
stack.pop(); // => 5

stack.items; // => undefined

items 已被移至 createStack() 作用域内。

这样修改后,从 createStack() 作用域的外部无法访问或修改 items 数组。现在 items 是一个私有变量,并且栈被封装:只有 push()pop() 方法是公共的。

push()pop() 方法是闭包,它们从 createStack() 函数作用域中得到 items 变量。

7. 智能乘法

编写一个函数  multiply() ,将两个数字相乘:

function multiply(num1, num2) {
  // 把你的代码写在这里...
}

要求:

如果用 2 个参数调用 multiply(num1,numb2),则应返回这 2 个参数的乘积。

但是如果用 1个参数调用,则该函数应返回另一个函数: const anotherFunc = multiply(num1) 。返回的函数在调用 anotherFunc(num2)  时执行乘法  num1 * num2

multiply(4, 5); // => 20
multiply(3, 3); // => 9

const double = multiply(2);
double(5);  // => 10
double(11); // => 22

答案

以下是  multiply()  函数的一种实现方式:

function multiply(number1, number2) {
  if (number2 !== undefined) {
    return number1 * number2;
  }
  return function doMultiply(number2) {
    return number1 * number2;
  };
}

multiply(4, 5); // => 20
multiply(3, 3); // => 9

const double = multiply(2);
double(5);  // => 10
double(11); // => 22

如果 number2 参数不是 undefined,则该函数仅返回 number1 * number2

但是,如果 number2undefined,则意味着已经使用一个参数调用了 multiply() 函数。这时就要返回一个函数 doMultiply(),该函数稍后被调用时将执行实际的乘法运算。

doMultiply() 是闭包,因为它从 multiply() 作用域中得到了number1 变量。

总结

如果你答对了 5 个以上,说明对闭包掌握的很好。如果你答对了不到 5 个,则需要好好的复习一下了。

原文地址:https://dmitripavlutin.com/simple-explanation-of-javascript-closures/

转载地址:https://segmentfault.com/a/1190000039366748

更多编程相关知识,请访问:编程视频!!

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!

Déclaration:
Cet article est reproduit dans:. en cas de violation, veuillez contacter admin@php.cn Supprimer