十年網(wǎng)站開(kāi)發(fā)經(jīng)驗(yàn) + 多家企業(yè)客戶 + 靠譜的建站團(tuán)隊(duì)
量身定制 + 運(yùn)營(yíng)維護(hù)+專業(yè)推廣+無(wú)憂售后,網(wǎng)站問(wèn)題一站解決
本篇內(nèi)容介紹了“關(guān)于閉包的面試題有哪些”的有關(guān)知識(shí),在實(shí)際案例的操作過(guò)程中,不少人都會(huì)遇到這樣的困境,接下來(lái)就讓小編帶領(lǐng)大家學(xué)習(xí)一下如何處理這些情況吧!希望大家仔細(xì)閱讀,能夠?qū)W有所成!
創(chuàng)新互聯(lián)長(zhǎng)期為上千客戶提供的網(wǎng)站建設(shè)服務(wù),團(tuán)隊(duì)從業(yè)經(jīng)驗(yàn)10年,關(guān)注不同地域、不同群體,并針對(duì)不同對(duì)象提供差異化的產(chǎn)品和服務(wù);打造開(kāi)放共贏平臺(tái),與合作伙伴共同營(yíng)造健康的互聯(lián)網(wǎng)生態(tài)環(huán)境。為舞鋼企業(yè)提供專業(yè)的成都網(wǎng)站建設(shè)、做網(wǎng)站,舞鋼網(wǎng)站改版等技術(shù)服務(wù)。擁有10年豐富建站經(jīng)驗(yàn)和眾多成功案例,為您定制開(kāi)發(fā)。
每個(gè) JavaScript 程序員都必須知道閉包是什么。在 JavaScript 面試中,你很可能會(huì)被問(wèn)到閉包的概念。
以下是 7 個(gè)有關(guān) JavaScript 閉包的面試題,比較有挑戰(zhàn)性。
不要查看答案或運(yùn)行代碼,看看自己的水平到底如何。做完這些題大約需要半小時(shí)左右。
1. 熱身
有以下函數(shù) clickHandler,immediate和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);
這3個(gè)函數(shù)中哪個(gè)能夠訪問(wèn)外部范圍變量?
答案:
clickHandler 能夠從外部作用域訪問(wèn)變量 countClicks。
immediate 無(wú)法訪問(wèn)外部作用域中的任何變量。
delayedReload 從全局作用域(也就是最外層作用域)中訪問(wèn)全局變量 location。
2. 丟失的參數(shù)
下列代碼輸出什么:
(function immediateA(a) { return (function immediateB(b) { console.log(a); // => ? })(1); })(0);
答案:
輸出為:0
用參數(shù) 0 調(diào)用 immediateA,因此 a 參數(shù)為 0。
immediateB 函數(shù)嵌套在 immediateA 函數(shù)中,是一個(gè)閉包,它從外部 immediateA作用域中得到 a 變量,其中 a 為 0。因此 console.log(a) 的輸出為 0。
3. 誰(shuí)是誰(shuí)
下面的代碼將會(huì)輸出什么內(nèi)容?
let count = 0; (function immediate() { if (count === 0) { let count = 1; console.log(count); // 輸出什么? } console.log(count); // 輸出什么? })();
答案:
輸出 1 和 0
第一個(gè)語(yǔ)句 let count = 0 聲明了一個(gè)變量 count。
immediate() 是一個(gè)閉包,它從外部作用域得到 count 變量。在 immediate() 函數(shù)作用域內(nèi), count 是 0。
但是,在條件內(nèi),另一個(gè) let count = 1 聲明了局部變量 count,該變量覆蓋了作用域之外的 count。第一個(gè) console.log(count) 輸出 1。
第二個(gè) console.log(count) 輸出為 0 ,因?yàn)檫@里的 count 變量是從外部作用域訪問(wèn)的。
4. 棘手的閉包
下列代碼輸出什么:
for (var i = 0; i < 3; i++) { setTimeout(function log() { console.log(i); // => ? }, 1000); }
答案輸出:
3, 3, 3。
代碼分為兩個(gè)階段執(zhí)行。
階段1:
for() 重復(fù) 3 次。在每次循環(huán)都會(huì)創(chuàng)建一個(gè)新函數(shù) log(),該函數(shù)將捕獲變量 i。setTimout() 安排log() 在 1000 毫秒后執(zhí)行。
當(dāng) for() 循環(huán)完成時(shí),變量 i 的值為 3。
階段2:
第二階段發(fā)生在 1000ms 之后:
setTimeout() 執(zhí)行預(yù)定的 log() 函數(shù)。log() 讀取變量 i 當(dāng)前的值 3,并輸出 3
所以輸出 3, 3, 3。
5. 錯(cuò)誤的信息
下面的代碼將會(huì)輸出什么:
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() 函數(shù)被調(diào)用 3 次,將 count 增加到 3。
message 變量存在于 createIncrement() 函數(shù)的作用域內(nèi)。其初始值為 'Count is 0'。但即使 count 變量已經(jīng)增加了幾次,message 變量的值也始終為 'Count is 0'。
log() 函數(shù)是一個(gè)閉包,它從 createIncrement() 作用域中獲取 message 變量。console.log(message) 輸出錄'Count is 0'到控制臺(tái)。
6. 重新封裝
下面的函數(shù) createStack() 用于創(chuàng)建棧結(jié)構(gòu):
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]; // 棧結(jié)構(gòu)的封裝被破壞了
它能正常工作,但有一個(gè)小問(wèn)題,因?yàn)楸┞读?stack.items 屬性,所以任何人都可以直接修改 items 數(shù)組。
這是一個(gè)大問(wèn)題,因?yàn)樗茐牧藯5姆庋b:應(yīng)該只有 push() 和 pop() 方法是公開(kāi)的,而 stack.items 或其他任何細(xì)節(jié)都不能被訪問(wèn)。
使用閉包的概念重構(gòu)上面的棧實(shí)現(xiàn),這樣就無(wú)法在 createStack() 函數(shù)作用域之外訪問(wèn) items 數(shù)組:
function createStack() { // 把你的代碼寫(xiě)在這里 } const stack = createStack(); stack.push(10); stack.push(5); stack.pop(); // => 5 stack.items; // => undefined
答案:
以下是對(duì) createStack() 的重構(gòu):
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() 作用域內(nèi)。
這樣修改后,從 createStack() 作用域的外部無(wú)法訪問(wèn)或修改 items 數(shù)組。現(xiàn)在 items 是一個(gè)私有變量,并且棧被封裝:只有 push() 和 pop() 方法是公共的。
push() 和 pop() 方法是閉包,它們從 createStack() 函數(shù)作用域中得到 items變量。
7. 智能乘法
編寫(xiě)一個(gè)函數(shù) multiply() ,將兩個(gè)數(shù)字相乘:
function multiply(num1, num2) { // 把你的代碼寫(xiě)在這里... }
要求:
如果用 2 個(gè)參數(shù)調(diào)用 multiply(num1,numb2),則應(yīng)返回這 2 個(gè)參數(shù)的乘積。
但是如果用 1個(gè)參數(shù)調(diào)用,則該函數(shù)應(yīng)返回另一個(gè)函數(shù):const anotherFunc = multiply(num1) 。返回的函數(shù)在調(diào)用 anotherFunc(num2) 時(shí)執(zhí)行乘法 num1 * num2。
multiply(4, 5); // => 20 multiply(3, 3); // => 9 const double = multiply(2); double(5); // => 10 double(11); // => 22
答案:
以下是 multiply() 函數(shù)的一種實(shí)現(xiàn)方式:
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 參數(shù)不是 undefined,則該函數(shù)僅返回 number1 * number2。
但是,如果 number2 是 undefined,則意味著已經(jīng)使用一個(gè)參數(shù)調(diào)用了 multiply() 函數(shù)。這時(shí)就要返回一個(gè)函數(shù) doMultiply(),該函數(shù)稍后被調(diào)用時(shí)將執(zhí)行實(shí)際的乘法運(yùn)算。
doMultiply() 是閉包,因?yàn)樗鼜?multiply() 作用域中得到了number1 變量。
“關(guān)于閉包的面試題有哪些”的內(nèi)容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業(yè)相關(guān)的知識(shí)可以關(guān)注創(chuàng)新互聯(lián)網(wǎng)站,小編將為大家輸出更多高質(zhì)量的實(shí)用文章!