这7道关于闭包的面试题,你能答对几个?

前端 2023-07-05 17:29:38
34阅读

每一个 JavaScript 程序猿都务必了解闭包是什么。在 JavaScript 招聘面试中,你很可能会被问起闭包的定义。

下列是 7 个相关 JavaScript 闭包的面试问题,较为有趣味性。

不必查看答案或运行代码,看一下自身的水准究竟怎样。做了这种题大概必须三十分钟上下。

1.  热身运动

有下列涵数 clickHandler,immediate和delayedReload:

 
  1. let countClicks = 0
  2. button.addEventListener('click', function clickHandler() { 
  3.   countClicks ; 
  4. }); 
  5. const result = (function immediate(number) { 
  6.   const message = `number is: ${number}`; 
  7.   return message; 
  8. })(100); 
  9. setTimeout(function delayedReload() { 
  10.   location.reload(); 
  11. }, 1000); 

这3个涵数中哪一个可以浏览外界范畴自变量?

回答:

  • clickHandler 可以从外界作用域浏览自变量 countClicks。
  • immediate 无法打开外界作用域中的一切自变量。
  • delayedReload 从全局性作用域(也就是最表层作用域)中浏览静态变量 location。

2. 遗失的主要参数

下述编码輸出哪些:

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

回答:

  • 輸出为:0
  • 用主要参数 0 启用 immediateA,因而 a 主要参数为 0。
  • immediateB 涵数嵌入在 immediateA 涵数中,是一个闭包,它从外界 immediateA作用域中获得 a 自变量,在其中 a 为 0。因而 console.log(a) 的輸出为 0。

3. 谁是谁

下边的编码可能輸出哪些內容?

 
  1. let count = 0
  2. (function immediate() { 
  3.   if (count === 0) { 
  4.     let count = 1
  5.     console.log(count); // 輸出哪些? 
  6.   } 
  7.   console.log(count); // 輸出哪些? 
  8. })(); 

回答:

  • 輸出 1 和 0
  • 第一个句子 let count = 0 申明了一个自变量 count。
  • immediate() 是一个闭包,它从外界作用域获得 count 自变量。在 immediate() 涵数作用域内, count 是 0。

可是,在标准内,另一个 let count = 1 申明了局部变量 count,该自变量遮盖了作用域以外的 count。第一个 console.log(count) 輸出 1。

第二个 console.log(count) 輸出为 0 ,由于这儿的 count 自变量是以外界作用域浏览的。

4. 繁杂的闭包

下述编码輸出哪些:

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

回答輸出:

  • 3, 3, 3。
  • 编码分成两个阶段实行。

环节1:

  • for() 反复 3 次。在每一次循环系统都是会建立一个新涵数 log(),该涵数将捕捉自变量 i。setTimout() 分配log() 在 1000 ms后实行。
  • 当 for() 循环系统过去进行时,自变量 i 的数值 3。

环节2:

第二阶段产生在 100ms 以后:

  • setTimeout() 实行预订的 log() 涵数。log() 载入自变量 i 当今的值 3,并輸出 3
  • 因此輸出 3, 3, 3。

5. 不正确的信息内容

下边的编码可能輸出哪些:

 
  1. function createIncrement() { 
  2.   let count = 0
  3.   function increment() {  
  4.     count ; 
  5.   } 
  6.  
  7.   let message = `Count is ${count}`; 
  8.   function log() { 
  9.     console.log(message); 
  10.   } 
  11.    
  12.   return [increment, log]; 
  13.  
  14. const [increment, log] = createIncrement(); 
  15. increment();  
  16. increment();  
  17. increment();  
  18. log(); // => ? 

回答:

輸出:'Count is 0'

  • increment() 涵数被启用 3 次,将 count 提升到 3。
  • message 自变量存有于 createIncrement() 涵数的作用域内。其初值为 'Count is 0'。但即便 count 自变量早已提升了几回,message 自变量的值也自始至终为 'Count is 0'。
  • log() 涵数是一个闭包,它从 createIncrement() 作用域中获得 message 自变量。console.log(message) 輸出录'Count is 0'到控制面板。

6. 再次封裝

下边的涵数 createStack() 用以建立栈构造:

 
  1. function createStack() { 
  2.   return { 
  3.     items: [], 
  4.     push(item) { 
  5.       this.items.push(item); 
  6.     }, 
  7.     pop() { 
  8.       return this.items.pop(); 
  9.     } 
  10.   }; 
  11.  
  12. const stack = createStack(); 
  13. stack.push(10); 
  14. stack.push(5); 
  15. stack.pop(); // => 5 
  16.  
  17. stack.items; // => [10] 
  18. stack.items = [10, 100, 1000]; // 栈构造的封裝被毁坏了 

它能一切正常工作中,但有一个小问题,由于曝露了 stack.items 特性,因此所有人都能够立即改动 items 二维数组。

这是一个问题,因为它毁坏了栈的封裝:应当仅有 push() 和 pop() 方式 是公布的,而 stack.items 或别的一切关键点都不可以被浏览。

应用闭包的定义重新构建上边的栈完成,那样就没法在 createStack() 涵数作用域以外浏览 items 二维数组:

 
  1. function createStack() { 
  2.   // 将你的编码写在这儿 
  3.  
  4. const stack = createStack(); 
  5. stack.push(10); 
  6. stack.push(5); 
  7. stack.pop(); // => 5 
  8.  
  9. stack.items; // => undefined 

回答:

下列是对 createStack() 的重新构建:

 
  1. function createStack() { 
  2.   const items = []; 
  3.   return { 
  4.     push(item) { 
  5.       items.push(item); 
  6.     }, 
  7.     pop() { 
  8.       return items.pop(); 
  9.     } 
  10.   }; 
  11.  
  12. const stack = createStack(); 
  13. stack.push(10); 
  14. stack.push(5); 
  15. stack.pop(); // => 5 
  16.  
  17. stack.items; // => undefined 

items 已被挪到 createStack() 作用域内。

那样改动后,从 createStack() 作用域的外界无法打开或改动 items 二维数组。如今 items 是一个独享自变量,而且栈被封裝:仅有 push() 和 pop() 方式 是公共性的。

push() 和 pop() 方式 是闭包,他们从 createStack() 涵数作用域中获得 items自变量。

7. 智能化加法

撰写一个涵数 multiply() ,将2个数据乘积:

 
  1. function multiply(num1, num2) { 
  2.   // 将你的编码写在这儿... 

规定:

假如用 2 个主要参数启用 multiply(num1,numb2),则应回到这 2 个主要参数的相乘。

可是假如用 一个主要参数启用,则该涵数应回到另一个涵数:const anotherFunc = multiply(num1) 。回到的涵数在启用 anotherFunc(num2) 时实行加法 num1 * num2。

 
  1. multiply(4, 5); // => 20 
  2. multiply(3, 3); // => 9 
  3.  
  4. const double = multiply(2); 
  5. double(5);  // => 10 
  6. double(11); // => 22 

回答:

下列是 multiply() 涵数的一种完成方法:

 
  1. function multiply(number1, number2) { 
  2.   if (number2 !== undefined) { 
  3.     return number1 * number2; 
  4.   } 
  5.   return function doMultiply(number2) { 
  6.     return number1 * number2; 
  7.   }; 
  8.  
  9. multiply(4, 5); // => 20 
  10. multiply(3, 3); // => 9 
  11.  
  12. const double = multiply(2); 
  13. double(5);  // => 10 
  14. double(11); // => 22 

假如 number2 主要参数并不是 undefined,则该涵数仅回到 number1 * number2。

可是,假如 number2 是 undefined,则代表着早已应用一个主要参数启用了 multiply() 涵数。这时候就需要回到一个涵数 doMultiply(),该涵数稍候被启用时将实行具体的乘法运算。

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

【责编:赵宁宁 TEL:(010)68476606】
关注点赞 0
the end
免责声明:本文不代表本站的观点和立场,如有侵权请联系本站删除!本站仅提供信息存储空间服务。