首頁 >web前端 >js教程 >7個JavaScript中關於閉包的面試題,你能回答上來嗎?

7個JavaScript中關於閉包的面試題,你能回答上來嗎?

青灯夜游
青灯夜游轉載
2021-03-26 09:41:575956瀏覽

7個JavaScript中關於閉包的面試題,你能回答上來嗎?

相關推薦:2021年大前端面試題總結(收藏)

每個JavaScript 程式設計師都必須知道閉包是什麼。在 JavaScript 面試中,你很可能會被問到閉包的概念。

以下是 7 個有關 JavaScript 閉包的面試題,比較有挑戰性。

不要查看答案或運行程式碼,看看自己的水平到底如何。做完這些題大約要半小時左右。

1. 範圍

有以下函數clickHandlerimmediatedelayedReload#:

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

這3個函數中哪一個能夠存取外部範圍變數?

答案

  • clickHandler 能夠從外部作用域存取變數 countClicks

  • immediate 無法存取外部作用域中的任何變數。

  • delayedReload 從全域作用域(也就是最外層作用域)存取全域變數 location

相關教學建議:javascript影片教學

#2.  遺失的參數

下列程式碼輸出什麼:

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

答案

輸出為:0

用參數0 呼叫immediateA,因此a 參數為0

immediateB 函數嵌套在immediateA 函數中,是一個閉包,它從外部immediateA 作用域中得到a 變量,其中a0。因此 console.log(a) 的輸出為 0

3. 誰是誰

下面的程式碼將會輸出什麼內容?

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

答案

輸出10

第一個語句 let count = 0 宣告了一個變數count

immediate() 是一個閉包,它從外部作用域得到 count 變數。在 immediate()  函數作用域內, count0

但是,在條件內,另一個let count = 1 宣告了局部變數count,該變數覆寫了作用域之外的count。第一個 console.log(count) 輸出 1

第二個 console.log(count) 輸出為 0 ,因為這裡的 count 變數是從外部作用域存取的。

4. 棘手的閉包

下列程式碼輸出什麼:

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

答案

輸出:3, 3, 3

程式碼分為兩個階段執行。

階段1

  1. for() 重複 3 次。在每次循環都會建立一個新函數 log(),該函數將捕獲變數 isetTimout() 安排log() 在 1000 毫秒後執行。
  2. for() 迴圈完成時,變數 i 的值為 3

階段2

第二階段發生在1000ms 之後:

  1. setTimeout() 執行預定的log() 函數。 log() 讀取變數i 目前的值3,並輸出3
##所以輸出

3, 3, 3

5. 錯誤的訊息

下面的程式碼將會輸出什麼:

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(); // => ?

答案

輸出:

'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() 用來建立堆疊結構:

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]; // 栈结构的封装被破坏了
它能正常工作,但有一個小問題,因為暴露了

stack.items 屬性,所以任何人都可以直接修改items 陣列。

這是一個大問題,因為它破壞了堆疊的封裝:應該只有

push()pop() 方法是公開的,而 stack.items 或其他任何細節都不能被存取。

使用闭包的概念重构上面的栈实现,这样就无法在 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

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

以上是7個JavaScript中關於閉包的面試題,你能回答上來嗎?的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文轉載於:segmentfault.com。如有侵權,請聯絡admin@php.cn刪除