ES6-2 块级作用域与嵌套、let、暂行性死区
注意,寫在開頭
function test(x = 1) {var x // 不報錯console.log(x) } function test1(x = 1) {let x = 10 // 報錯console.log(x) }let的變量名不可以和參數中的名稱相同。而var并不限制,說白了就是希望你規范使用變量名。
形參原則上數組函數內部的臨時變量,但是形參其實在內存中有獨立的空間存儲。
阮一峰ES6 - let
思考,在編寫代碼時,有es5、es6的語法,究竟是否有塊級作用域?
ES6 明確規定,如果區塊中存在let和const命令,這個區塊對這些命令聲明的變量,從一開始就形成了封閉作用域。
1. var關鍵字可以重復聲明
var num1 = 1; var num1 = 100; console.log(num1) // 1002. let塊級作用域
2.1 同一作用域下不能重復聲明(無論是let/var/const聲明)
let num1 = 1; var num1 = 100; // 報錯 重復定義 var a = 10; let a = 10; // 報錯 function test(a){let a = 10; // 預編譯時,形參a已定義,重復聲明報錯 } let a = 1; function a() { } // 報錯 let a = 1; {function a() { } // 不報錯 } // 函數提升是在當前(塊級)作用域下提升 // 轉譯后 "use strict";var a = 1; {var _a = function _a() {}; // 不報錯} function test(a) {{let a = 10;}console.log(a) // undefined } test()2.2 let不會提升,會產生一個暫時性死區,在變量聲明前訪問會報錯
var a = a; console.log(a) // undefined let x = x; // 報錯 // 在變量x的聲明語句還沒有執行完成前,就去取x的值,導致報錯”x 未定義“。 // 這里不要把賦值語句拆分為聲明和賦值2步理解- 以下3種情況
↓
// 轉譯ES5 "use strict";var x = 1; {var _x = _x;console.log(_x); // undefined }這里注意: 因為es5不存在暫時死區。let x = x 的問題在于,右側x是取值并賦值的操作,而這個時候在es6里,x并沒有完成初始化,所以取值x的時候就會失敗。
而var是不存在這種問題的。因為es6嚴格規定了初始化流程就是變量聲明必須初始化且不允許取值。也就是說聲明語句不可以有對該變量的引用。
轉譯并不能百分百還原。對應let轉var這里就出現了以上的情況。
有些瀏覽器不支持塊級作用域(大括號)。
轉譯結果和babel的版本也有關系,有可能轉譯后去除了大括號或轉成IIFE或其他形式。
↓
"use strict";var x = 1; {var _x;_x = _x;console.log(_x); // undefined } // 這個本身就是ES5不需要轉 var x = 1; {x = x;console.log(x) // 1 } let a ; a = a console.log(a) // undefined if (true) {// TDZ開始tmp = 'abc'; // ReferenceErrorconsole.log(tmp); // ReferenceErrorlet tmp; // TDZ結束console.log(tmp); // undefinedtmp = 123;console.log(tmp); // 123 } function bar(x = y, y = 2) {return [x, y]; }bar(); // 報錯 // 參數x默認值等于另一個參數y,而此時y還沒有聲明,屬于“死區”。如果y的默認值是x,就不會報錯,因為此時x已經聲明了。2.3 typeof不再是一個百分之百安全的操作
typeof x; // ReferenceError let x;注意
for (var i = 0; i < 10; i++) {arr[i] = function () {console.log(i)} } for (var i = 0; i < 10; i++) {arr[i]() // 打印0-9 } // 第二個for循環里,var i重新賦值了,恰好是i var arr = []; for (var i = 0; i < 10; i++) {arr[i] = function () {console.log(i)} } // 上個for循環var i是全局的,退出循環后為10 for (var index = 0; index < 10; index++) {arr[index]() // 10個10 }==================================================
let是在塊中聲明的變量,每當聲明一個function都會傳入當前for的塊中單獨的i進去。也就是說let是塊變量,在自己的塊,或者子塊中使用。而不是只在函數或全局作用域中使用。立即執行函數是為了將每次的i作為函數作用域中的局部變量傳入與外界的i隔離。
// 用let聲明,由于存在父子級作用域,相當于也形成了閉包 var arr = []; for (let i = 0; i < 10; i++) {arr[i] = function () {console.log(i)} } // 即使index用let打印的也是0-9 for (var index = 0; index < 10; index++) {arr[index]() // 0-9 } // 轉譯之后 "use strict";var arr = [];var _loop = function _loop(i) {arr[i] = function () {console.log(i);}; };for (var i = 0; i < 10; i++) {_loop(i); // 這里立即執行了 }for (var index = 0; index < 10; index++) {arr[index](); // 0-9 }2.4 for循環作用域
- for循環的特別之處,就是設置循環變量的那部分是一個父作用域,而循環體內部是一個單獨的子作用域
以前遇到的有IIFE里不用關鍵字聲明的嗎
let a = 1; (function(){a = 10; console.log(a) // 10 })() console.log(a) // 10 let a = 1; (function(){let a = 10;console.log(a) // 10 })() console.log(a) // 1 var a; (function () {a = 10;console.log(a) // 10 })(); (function () {a = 100;console.log(a) // 100 })(); console.log(a) // 100 (function () {var a = 10;console.log(a) // 10 })(); (function () {var a = 100;console.log(a) // 100 })(); console.log(a) // 報錯 // Uncaught ReferenceError: a is not defined思考:在index.html文件的script標簽里編碼,既有es5的語法,又有es6的語法,在瀏覽器中打開時,瀏覽器會將所有代碼轉譯成es6嗎
不會轉譯,瀏覽器不同的版本對es的支持不一樣。(現代瀏覽器基本都支持ES6)
現在普遍兼容es6的語法。但對特殊的語法需要babel轉譯, 包括對象的拓展,類的修飾等等,這些是需要babel轉譯的。
塊級作用域等于匿名函數的立即調用嗎?并不,塊級作用域沒有返回值。二者本質不同。
思考總結,在塊級作用域{}內,用let/const聲明的和父作用域同名的變量x,在轉譯ES6的時候,會被編譯成另一變量_x
創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎總結
以上是生活随笔為你收集整理的ES6-2 块级作用域与嵌套、let、暂行性死区的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 苹果笔记本摄像头linux驱动下载,更适
- 下一篇: android手机怎么root,安卓手机