鍍金池/ 問答/網(wǎng)絡(luò)安全  HTML/ 閉包經(jīng)典面試題,請教各位

閉包經(jīng)典面試題,請教各位

首先是一道前端經(jīng)典閉包面試題。

for(var i = 0;i<5;i++){
  setTimeout(()=>{
    console.log(i)
  },1000*i)
}

這題大家都知道答案是每隔1秒打出5。

然后面試官讓改成每隔1秒輸出正確數(shù)字,你知道使用閉包:

function a(j){
  setTimeout(()=>{
     console.log(j)
  },1000*j)
}
for(var i = 0;i<5;i++){
  a(i)
}

但是這樣的做法只是使用函數(shù)作用域保存了i的值,讓定時器執(zhí)行回調(diào)時所找到的變量值是每次循環(huán)對應(yīng)的值,而閉包的作用是讓函數(shù)外部間接訪問到函數(shù)內(nèi)部的值。

所以簡單來說我覺得這道題不是閉包的作用,而僅僅是函數(shù)作用域的作用。

不知道我的理解對不對。

回答
編輯回答
念初

閉包是函數(shù)內(nèi)部有權(quán)訪問函數(shù)外部的變量,不是外部訪問內(nèi)部

首先看下完整版 破解前端面試(80% 應(yīng)聘者不及格系列):從 閉包說起

其實主要利用了基本類型在函數(shù)調(diào)用時,按值傳遞的,所以就能拿到不同時期 i 對應(yīng)的值,跟閉包沒多大關(guān)系。

2018年4月9日 15:57
編輯回答
別逞強

一句話,在 js 中,函數(shù)參數(shù)是按照值來傳遞的

2017年1月3日 21:56
編輯回答
卟乖

一般這種套路讓你寫的是立即執(zhí)行函數(shù)表達(dá)式,當(dāng)然更任性的會改成let。

for(var i = 0;i<5;i++){
  (setTimeout((j)=>{
    console.log(j)
  },1000*j))(i)
}

閉包應(yīng)該是指的原題,setTimeout的callback引用了不屬于其作用域的變量i,i在原有的作用域上無法釋放。當(dāng)然,你也可以理解為所有的異步操作都是閉包。

你不知道的JavaScript中關(guān)于閉包的定義

當(dāng)函數(shù)可以記住并訪問所在的詞法作用域,即使函數(shù)是在當(dāng)前詞法作用域之外執(zhí)行,這時
就產(chǎn)生了閉包。-----你不知道的JavaScript

你回答的答案沒錯,但是作用域和閉包密切相關(guān),這里很容易覺得沒有閉包,但事實上這是關(guān)于詞法作用域的問題,以下兩段代碼,1在詞法作用域內(nèi),2在詞法作用域外。

function a(){
    function b(){
    }
}
function a(){
    setTimeout(function b(){
    },0);
}
2017年4月29日 19:59
編輯回答
淺淺

你說對了……一半!

function a(j){
  setTimeout(()=>{ // callback
     console.log(j)
  },1000*j)
}
for(var i = 0;i<5;i++){
  a(i)
}

這是一個作用域問題,同時也是一個閉包問題。

關(guān)鍵點在于setTimeout定時器所執(zhí)行的函數(shù)會脫離當(dāng)前的作用域,callback函數(shù)并不是在a函數(shù)的作用域中執(zhí)行的,其中的ja中那個j的閉包變量。

換句話說,如果沒有閉包,callback函數(shù)中訪問到的將是undefined(或報錯)。

2017年12月26日 16:03
編輯回答
老梗

沒毛病,但是這倆概念也不沖突啊,不傳參數(shù),直接用函數(shù)外的值就不是作用域了嗎,也是作用域啊。
我一直覺得用到外部作用域的變量或者值都算閉包,把閉包當(dāng)作一個現(xiàn)象比較好,作用域是原因,什么執(zhí)行完不銷毀還保持引用就是個“特殊”的作用域現(xiàn)象。

2017年3月8日 21:53
編輯回答
檸檬藍(lán)

閉包的預(yù)期行為就是把對外部內(nèi)存的引用封進(jìn)函數(shù)里,只是JS程序員對指針內(nèi)存地址之類的比較沒有概念,會認(rèn)為第一種情況是錯誤的,其實那才是正確的表現(xiàn)。

至于怎么把結(jié)果改成第二種情況就跟閉包這一概念無關(guān)了,不同語言有不同的解決方式,JS里大家經(jīng)常踩進(jìn)這坑比較津津樂道。

2017年11月10日 15:50
編輯回答
忠妾
for(let i = 0;i<5;i++){
  setTimeout(()=>{
    console.log(i)
  },1000*i)
}//0,1,2,3,4
2017年10月25日 11:48