摘要:塊狀作用域提起中的關鍵字,第一個想法就是塊狀作用域。而如果通過這些關鍵詞聲明的,那么也就會聲明到所在的作用域中。終于回到可以將變量綁定到所在的任意作用域中,通常是內部。避免不必要的出現。
讀<你不知道的javascript>,想到哪里寫到哪里。。。
塊狀作用域提起ES6中的let關鍵字,第一個想法就是塊狀作用域。
說到作用域,以前提及的都是全局作用域和函數作用域。當進行作用域查找的時候,永遠是一層一層往上查找,直到找到第一個匹配的標示符時停止。
全局作用域就是整個作用域的最上層,當進行作用域查找的時候,全局作用域永遠是最上一層,如果在全局作用域中依然無法找到,那么就會拋出referenceError。
而說到函數作用域,曾經讀過一本書上面說到一個詞“隱藏”變量和函數定義,覺得很貼切。把東西隱藏在函數中,避免污染外部作用域的同時,可以有效地進行模塊化管理。
回到塊狀作用域,除了let,另外一個with關鍵字也創造了一個塊狀作用域。
function foo(obj) { var c = 6; with(obj) { a = b; c = 5; var d = 7; let e = 8; } console.log(c); // 5 console.log(d); // 7 console.log(e); // referenceError } var obj = { a:1, b:2 }; foo(obj);
我們都知道其中的a和b的作用域查找(LHS, RHS)都是在obj中找到。而如果無法再obj中找到,那么就會向上作用域繼續找,這里的c就會找到foo函數中的c。而如果通過var這些關鍵詞聲明的,那么也就會聲明到with所在的作用域中。
對于with,就相當于在外面又包了一層作用域,里面包含提供對象中的所有屬性。
終于回到let, let可以將變量綁定到所在的任意作用域中,通常是{}內部。沒了。。。
提升和var聲明變量和函數聲明,let不會進行提升。看看下面的幾個例子:
console.log(a); // referenceError let a = 1;
console.log(b); // undefined; var b = 1;
foo(); // 3 function foo(){ console.log("3") }
foo(); // type error var foo = function(){ console.log("4") }
foo(); // referenceError let foo = function(){ console.log("5") }
說到提升,提一句:“函數會首先被提升,然后才是變量”。像之前的書里的一個例子:
bar(); // 3 function bar(){ console.log(1) }; var bar = function(){ console.log(2) }; function bar(){ console.log(3) }
提升以后看起來就像:
function bar(){ console.log(1) }; function bar(){ console.log(3) }; bar(); // 3 bar = function(){ console.log(2) };
這里需要提一句,var bar這一段由于bar在之前已經被聲明過了,所以這里var bar會被忽略,而不是把bar設為null。
說到提升,還有一種特殊的情況,雖然不建議這么寫,但是肯定會有人會踩到雷:
var a = true; if(a) { function foo(){ console.log(1) } } else { function foo(){ console.log(2) } } foo();
原書中說這種情況,由于提升,所以會輸出2,而不是我們想要的1。但是我在chrome和firefox中試了一下,會按照想要的輸出1。而在IE11中,卻輸出的是2。
所以,很明顯,chrome和firefox對這種情況作了優化,但是還是有瀏覽器的差別,所以盡量不要這么聲明函數。避免不必要的bug出現。
垃圾收集當使用閉包的時候,會造成一部分的內存不會進行釋放。這是閉包的好處,也是閉包的壞處。好處就是我們可以在外部使用這個變量,而壞處就是有些不需要的變量也不會被釋放。
一個簡單的閉包:
function Foo(){ var a = [....]; // .....和a做些互動 var b = 0; return function(){ return b++; } }
這里在閉包中,我們其實只需要保存b的內存就好,而a是不需要的。按照理想情況,a在Foo結束后就可以垃圾回收了(GC)。然而引擎有可能會保存著這個東西(取決于具體實現--你不知道的javascript),這就造成了內存的浪費。
那么就可以使用let塊狀作用域的特性,進行處理:
function Foo(){ { let a = [....]; // ....和a做些互動 } var b = 0; return function(){ return b++; } }
這里,由于a的作用域只在{}中,所以當{}結束后就會釋放a的內存,而不是長久占有內存。
循環這里只寫出一個很有意思的觀點。
我們都知道在循環中用let可以解決某個老生常談的問題。但是總是轉變不過來,為什么會解決這個問題。
var a = []; for(var i = 0; i < 10; i++) { a[i] = function(){ console.log(i) }; } a[3](); // 10
var a = []; for(let i = 0; i < 10; i++) { a[i] = function(){ console.log(i) }; } a[3](); // 3
所以到底let做了什么神奇的事情,解決了這個問題?
書中說了一句話:
for循環頭部的let不僅將i綁定到了for循環的塊中,事實上它將其重新綁定到了循環的每一個迭代中,確保使用上一個循環迭代結束時的值重新進行賦值。
然后給了一個等價的例子,一目了然:
var a = []; { let j; for(j=0; j<10;j++){ let i = j; // 每個迭代重新綁定 a[i] = function(){ console.log(i) }; } } a[3](); // 3
最后啰嗦一句,const這個關鍵詞,也是塊狀作用域,也是不提升。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/82421.html
摘要:前面不短時間持續投入了時間在做應用架構方面的考量一個是冒險進行了一次應用架構的調整另一個是跟進了的進展當然實際上是同一個事情也許錯過的比收獲的還多一些不過能走到現在也算幸運了畢竟單頁面應用還面臨很多不成熟之處國慶長假過去不少現在的想法估計會 前面不短時間持續投入了時間在做 React 應用架構方面的考量一個是冒險進行了一次應用架構的調整, 另一個是跟進了 Redux 的進展當然, 實際...
摘要:背景如圖所示馮諾依曼計算機體系結構由于最近做業務需求做到發瘟借此發散一下思維最近業務需求的痛點如下基礎代碼骨架已固定業務流程固定然而業務中產品的配置需要非常靈活并且有可能需要跨過某段業務流程直接執行下一段直接方案當然是能夠決定條件分支的但架 showImg(https://segmentfault.com/img/bVbrHbo?w=1920&h=981); 背景 如圖所示, 馮諾依曼...
閱讀 2073·2021-09-22 15:54
閱讀 1834·2021-09-04 16:40
閱讀 861·2019-08-30 15:56
閱讀 2629·2019-08-30 15:44
閱讀 2154·2019-08-30 13:52
閱讀 1125·2019-08-29 16:35
閱讀 3347·2019-08-29 16:31
閱讀 2567·2019-08-29 13:48