填坑-十万个为什么?(13)
生活随笔
收集整理的這篇文章主要介紹了
填坑-十万个为什么?(13)
小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.
簡介:很多概念不清或忘記,重新構(gòu)建自己的知識體系。每天問自己1~多個問題。我是菜鳥 成為大神之路!
1. 經(jīng)典面試題 for(var i=0;i<=3;i++){ setTimeout(function() { console.log(i) }, 10);}打印結(jié)果?分析?
for(var i = 0; i < 10; i++) {console.log(new Date(),i);setTimeout(() => {console.log(new Date(),i)}, 1000);//一秒 } 答案:打印10個10這道題涉及了異步、作用域、閉包?settimeout是異步執(zhí)行,1ms后往任務(wù)隊列里面添加一個任務(wù),只有主線上的全部執(zhí)行完,才會執(zhí)行任務(wù)隊列里的任務(wù), 當(dāng)主線執(zhí)行完成后,i是10,所以此時再去執(zhí)行任務(wù)隊列里的任務(wù)時,i全部是10了。?對于打印10次是:每一次for循環(huán)的時候,settimeout都執(zhí)行一次,但是里面的函數(shù)沒有被執(zhí)行,而是被放到了任務(wù)隊列里面, 等待執(zhí)行,for循環(huán)了10次,就放了10次,當(dāng)主線程執(zhí)行完成后,才進入任務(wù)隊列里面執(zhí)行。 (注意:for循環(huán)從開始到結(jié)束的過程,需要維持幾微秒或幾毫秒。) 復(fù)制代碼① 若要輸出從0到9,將 var 改為 let
for(let i = 0; i < 10; i++) {console.log(new Date(),i);setTimeout(() => {console.log(new Date(),i)}, 1000);//一秒 }當(dāng)我把var 變成let 時 ?打印出的是:0~10當(dāng)解決變量作用域,因為for循環(huán)頭部的let不僅將i綁定到for循環(huán)快中, 事實上它將其重新綁定到循環(huán)體的每一次迭代中,確保上一次迭代結(jié)束的值重新被賦值。?setTimeout里面的function()屬于一個新的域,通過 var 定義的變量是無法傳入到這個函數(shù)執(zhí)行域中的, 通過使用 let 來聲明【塊變量】,這時候變量就能作用于這個塊,所以 function就能使用 i 這個變量了;?這個匿名函數(shù)的參數(shù)作用域 和 for參數(shù)的作用域不一樣,是利用了這一點來完成的。 這個匿名函數(shù)的作用域有點類似類的屬性,是可以被內(nèi)層方法使用的。 復(fù)制代碼② 若要輸出從0到9,改寫為閉包
閉包相關(guān)解釋下一問。
// 使用閉包 for(var i = 0; i < 10; i++) {console.log(new Date(),i);(function (i) {setTimeout(() => {console.log(new Date(),i);}, 1000);})(i); } 復(fù)制代碼2.閉包的作用域?代碼執(zhí)行過程?
經(jīng)常遇到閉包的相關(guān)問題
代碼一: // 以1問中例子為例 for(var i = 0; i < 10; i++) {console.log(new Date(),i);(function (i) {setTimeout(() => {console.log(new Date(),i);}, 1000);})(i); } 代碼一是閉包,寫為代碼二不為閉包的形式,(function(i){})(i) '理解為自執(zhí)行函數(shù)' 自執(zhí)行函數(shù)的相關(guān)參考在12天和參考文章中,之后我會對著一塊內(nèi)容進行學(xué)習(xí)?。代碼二: var fun = function(x){setTimeout(() => {console.log(new Date(),x);}, 1000);}for(var i = 0; i < 10; i++) {console.log(new Date(),i);fun(i); } 復(fù)制代碼JavaScript 變量可以是局部變量或全局變量。 私有變量可以用到閉包。什么是閉包: > 就是函數(shù)的局部變量集合,只是這些局部變量在函數(shù)返回后會繼續(xù)存在。 > 就是函數(shù)的“堆棧”在函數(shù)返回后并不釋放,我們也可以理解為這些函數(shù)堆棧并不在棧上分配而是在堆上分配 > 當(dāng)在一個函數(shù)內(nèi)定義另外一個函數(shù)就會產(chǎn)生閉包 > "注:變量聲明時如果不使用 var 關(guān)鍵字,那么它就是一個全局變量,即便它在函數(shù)內(nèi)定義。"注意:通常人們對閉包的理解是不完全的,認為在 JavaScript 中只有嵌入的函數(shù)才是閉包。但其實任何擁有 free variable(自由變量) 的函數(shù)都是以閉包的形式存在的。因為本質(zhì)上,閉包是 free variable 問題的一種解決方案。http://liximomo.github.io/javascript-closure閉包的注意點 1)由于閉包會使得函數(shù)中的變量都被保存在內(nèi)存中,內(nèi)存消耗很大,所以不能濫用閉包,否則會造成網(wǎng)頁的性能問題,在IE中可能導(dǎo)致內(nèi)存泄露。 解決方法是,在退出函數(shù)之前,將不使用的局部變量全部刪除。 2)閉包會在父函數(shù)外部,改變父函數(shù)內(nèi)部變量的值。所以,如果你把父函數(shù)當(dāng)作對象(object)使用,把閉包當(dāng)作它的公用方法(Public Method), 把內(nèi)部變量當(dāng)作它的私有屬性(private value),這時一定要小心,不要隨便改變父函數(shù)內(nèi)部變量的值。 復(fù)制代碼閉包需要注意的兩種情況----函數(shù)作為返回值,函數(shù)作為參數(shù)傳遞。
例子:函數(shù)作為返回值
1. function greeting(name) { 2. var text = 'Hello '; // local variable// 每次調(diào)用時,產(chǎn)生閉包,并返回內(nèi)部函數(shù)對象給調(diào)用者 3. return function() {return text += name; }}4. var sayHello=greeting("Closure");5. document.write(sayHello()); 6. document.write("<br>"); 7. document.write(sayHello()); 8. document.write("<br>"); 9. document.write(sayHello()); 10. document.write("<br>"); 11. document.write(sayHello()); 12. document.write("<br>"); 13. document.write(sayHello());// 通過閉包訪問到了局部變量text代碼解析: > 執(zhí)行第4行時第一行的函數(shù)運行一次,返回內(nèi)嵌函數(shù)引用作為第4行sayHello變量的值。 > 之后的第5到13行執(zhí)行的函數(shù)操作其實只是執(zhí)行sayHello指向的函數(shù)(即返回的內(nèi)嵌函數(shù))。 > 解釋text為什么能自增,閉包的概念。復(fù)制代碼例子:函數(shù)作為參數(shù)傳遞
1. var num = 10;2. var fun = function(var num){ 3. console.log(num);} 4. !function(f){ 5. var num = 100; 6. f(num); 7. }(fun)代碼解析: > 第四行'!'表示高優(yōu)先級,被'!'標(biāo)注的先執(zhí)行。 > 第7行將fun指向的引用2行函數(shù)傳給參數(shù)f在函數(shù)中執(zhí)行f(?)函數(shù),此時log出來的值是10。 > 解釋看js作用域 復(fù)制代碼3.var let const的區(qū)別?
① 什么是var的變量提升補充2019年1月5日23:31:41 來源網(wǎng)易課堂
'代碼1' var a = 10; function foo(){console.log(a);//打印:10 } '代碼2' var a = 10; function foo(){console.log(a);//打印:undefinedvar a = 5; } '問代碼2為什么輸出的是undefined這里變量提前了,實際代碼相當(dāng)于如下' '代碼3' var a = 10; function foo(){var a;console.log(a);//打印:undefineda = 5; } 復(fù)制代碼② let 聲明的變量只在它所在的代碼塊有效
function demo(){{var a = 12;let c = 10;console.log(a);//這里會打印出12;console.log(c);//這里會打印出10;}console.log(a);//這里會打印出12console.log(c);//這里打印出的內(nèi)容為 "c is not defined";//說明聲明的c變量只在{}代碼塊中能夠訪問,其他地方都訪問不到; } demo(); 復(fù)制代碼③ let不存在變量提升
let 不像var 那樣會發(fā)生 '變量提升' 現(xiàn)象,因此,變量需要先聲明然后再使用,否則報錯;
// var 的情況 console.log(vardata); // undefined var vardata = 2;// let的情況; console.log(letdata); // letdata is not defined 報錯 let letdata = 2; 復(fù)制代碼④ let暫時性死區(qū)
快級作用域內(nèi)存在let命令,它所聲明的變量就綁定在這個區(qū)域,不再受外部影響;
var tmp = 123; if (true) {tmp = 'abc';let tmp;console.log(tmp); // tmp is not defined } 復(fù)制代碼⑤ let不允許重復(fù)聲明
let 不允許在相同作用域內(nèi),重復(fù)聲明同一個變量。
function foo() {let v = 10;var v = 1;//Identifier 'v' has already been declaredconsole.log(v); } foo();function foo1() {let v1 = 10;let v1 = 1;//Identifier 'v1' has already been declaredconsole.log(v1); } foo1(); 復(fù)制代碼⑥ const 聲明一個只讀的常量,一旦聲明,常量的值就不允許改變
⑦ const 一旦聲明了變量,就必須初始化,不能留到以后賦值。如果使用const聲明一個變量,但是不賦值,也會報錯
⑧ const 的作用域與let命令相同;只在聲明所在的塊級作用域內(nèi)有效。
⑨ const 不可重復(fù)聲明 (和let一樣)
參考文章:
① let的含義及l(fā)et與var的區(qū)別
② 閉包文檔
③ 博客-深入理解javascript原型和閉包
④ JS關(guān)于閉包
⑤ 函數(shù) + 函數(shù)創(chuàng)建時的環(huán)境 = 閉包
轉(zhuǎn)載于:https://juejin.im/post/5c26e9cbe51d450cfe737dae
總結(jié)
以上是生活随笔為你收集整理的填坑-十万个为什么?(13)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 已触发了一个断点 vs_VSCode源码
- 下一篇: 2019我的目标