Maison > Article > interface Web > 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.
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 ?
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
Le code suivant. Qu'est-ce que le résultat :
(function immediateA(a) { return (function immediateB(b) { console.log(a); // => ? })(1); })(0);
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
.
Que produira le code suivant ?
let count = 0; (function immediate() { if (count === 0) { let count = 1; console.log(count); // 输出什么? } console.log(count); // 输出什么? })();
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.
Que produit le code suivant :
for (var i = 0; i < 3; i++) { setTimeout(function log() { console.log(i); // => ? }, 1000); }
Sortie : 3
, 3
, 3
.
Le code est exécuté en deux étapes.
Phase 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. for()
se termine, la variable i
a la valeur 3
. Phase 2
La deuxième phase se produit après 1000 ms :
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
.
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(); // => ?
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.
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
变量。
编写一个函数 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
。
但是,如果 number2
是 undefined
,则意味着已经使用一个参数调用了 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!