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) // 100

2. 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種情況
var x = 1;
{// 此處=右的x取的是塊級作用域內的// 暫時性死區let x = x;console.log(x) // 報錯// Uncaught ReferenceError: Cannot access 'x' before initialization
}

// 轉譯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或其他形式。

var x = 1;
{let x;x = x;console.log(x) // undefined
}

"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循環的特別之處,就是設置循環變量的那部分是一個父作用域,而循環體內部是一個單獨的子作用域
for (var i = 0; i < 10; i++) {let i = 'a' console.log(i) // 10個a // 循環的index i是聲明在全局的
}
console.log(i) // 10
for (let i = 0; i < 10; i++) {// for循環內的塊級作用域// for花括號內的塊級作用域并不相同let i = 'a'console.log(i) // 10個a
}
for (let i = 0; i < 10; i++) {var i = 'a' // 報錯 // 因為for循環內,這里var聲明的i會提升到全局// 而for循環條件又用let聲明一次i,重復聲明了console.log(i) 
}
if (1) {let a = 1;console.log(a) // 1{let a = 10;console.log(a) // 10}
}

以前遇到的有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

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/251041.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/251041.shtml
英文地址,請注明出處:http://en.pswp.cn/news/251041.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

常用的操作系統知識

為什么要有操作系統 現代計算機系統是由一個或者多個處理器&#xff0c;主存&#xff0c;磁盤&#xff0c;打印機&#xff0c;鍵盤&#xff0c;鼠標顯示器&#xff0c;網絡接口以及各種其他輸入&#xff0c;輸出設備組成的復雜系統&#xff0c;每位程序員不可能掌握所有系統實現…

vue --- 使用中央事件總線(bus)實現跨組件通信

使用Bus實現跨組件傳輸須注意以下3點: 1.需要創建一個空的Vue實例(bus),來作為中間站 2.使用bus.emit來發送事件3.使用bus.emit來發送事件 3.使用bus.emit來發送事件3.使用bus.on來監聽事件(在鉤子created中監聽) 代碼如下: <!DOCTYPE html> <html> <head>…

Execution Order of Event Functions, unity 3d 事件函數的執行順序

vs_Community.exe --layout "F:\linson\vs2017 comm\offline" --lang zh-CN 學習unity3d&#xff0c;感覺事件順序很重要。就翻譯一下官方文檔吧。 Execution Order of Event Functions 事件函數的執行順序 In Unity scripting, there are a number of event functio…

ES6-3 let進階、const、全部變量與頂層對象

一 const 1. 定義常量 1.1 引入模塊時 const test require(http)1.2 定義時必須賦值(初始化)且不可修改 const a; // Uncaught SyntaxError: Missing initializer in const declaration若賦值為原始值&#xff0c;不可修改若賦值為引用值&#xff0c;對于的地址不可修改&a…

前后端如何通信

目錄 前后端如何通信URL . URI . URN第一部分&#xff1a;傳輸協議第二部分&#xff1a;域名第三部分&#xff1a;端口號第四部分&#xff1a;請求資源文件的路徑名稱第五部分&#xff1a;問號傳參第六部分&#xff1a;HASH值前后端如何通信 前段&#xff1a;客戶端 后端&#…

vue --- 獲取子組件數據的一個應急方案$refs

使用$refs需要注意以下2點: 1.html方法使用子組件時,需使用ref “xxx” 聲明. 2.在父組件中使用,this.refs.xxx.msg 獲取數據 <!DOCTYPE html> <html> <head> <meta charset"utf-8"> </head> <body><div id"app"…

Mysql 根據出生日期計算年齡

最近因為業務要求需要根據出生日期計算年齡&#xff0c;在網上查了好多的方法&#xff0c;在這里總結一下。 網上的計算方法好多都提到了格里高利歷法&#xff0c;特意去查了下資料&#xff0c;普及點知識。 格里高利歷是公歷的標準名稱&#xff0c;是一種源自于西方社會的歷法…

ES6-4/5 解構賦值、函數默認值、數組解構、對象解構

ES-4 解構賦值、函數默認值、數組解構、對象解構 ES-5 隱式轉換、函數參數解構、解構本質、()用法 一 解構賦值 1 虛值 含義&#xff1a;在Boolean轉換結果為假的值falsy 2 函數默認值 ES6 內部使用嚴格相等運算符&#xff08;&#xff09;&#xff0c;判斷一個位置是否有值…

springboot之session、cookie

1- 獲取session的方案 session: https://blog.csdn.net/yiifaa/article/details/77542208 2- session什么時候創建&#xff1f; 一個常見的誤解是以為session在有客戶端訪問時就被創建&#xff0c;然而事實是直到某server端程序調用HttpServletRequest.getSession(true)這樣…

echarts --- 多折線圖按段顯示顏色規則訂制

描述: 圖中有4個序列,序列1和序列2在同一個x軸下,顯示不同的顏色.(如,在-40到-30,序列一是紅色,而序列2是黑色) 關鍵: VisualMap中的seriesIndex屬性(根據不同的系列,制定不同的顏色規則). 下面是代碼,可以直接復制到 echart實例 中進行調試 var symbolSize 20; var data [[…

Git-分布式版本控制系統

一、版本控制 版本控制系統是記錄若干文件內容變化&#xff0c;以便將來查閱修訂特定版本或還原部分文件的系統 分為&#xff1a;集中式版本控制系統&#xff08;svn&#xff09;簡稱cvcs 都有一個單一集中管理服務器&#xff0c;保存所有文件修訂版本&#xff0c;開發人員通…

ES6-6 - this指向、箭頭函數基本形式、rest運算符

一 chrome斷點調試 觀察函數調用棧 // 25min var x 1; function foo(x, y function () { x 2; console.log(2) }) {var x 3;y();console.log(x) } foo() console.log(x) // 2 3 1var x 1; function foo(x, y function () { x 2; console.log(x) }) {x 3;y();console.…

【二分答案】Problem C:木材加工

Problem C:木材加工 Time Limit:1000MS Memory Limit:65536K Total Submit:48 Accepted:20 Description 【問題描述】 木材廠有一些原木&#xff0c;現在想把這些木頭切割成一些長度相同的小段木頭&#xff08;木頭有可能有剩余&#xff09;&#xff0c;需要得到的小段的數目是…

vue --- vue.js實戰基礎篇課后練習

練習1:在輸入框聚焦時,增加對鍵盤上下鍵按鍵的支持,相當于加1和減1 練習2:增加一個控制步伐的prop-step,比如設置為10,點擊加號按鈕,一次增加10 思路: // 考慮到子模板的復用性,即在父模板中復用如下: <input-number v-model"value" :max"10" :min&qu…

js打字效果

//文字依次出來效果 $.fn.autotype function() {var $text $(this);// console.log(this, this);var str $text.html(); //返回被選 元素的內容var index 0;var x $text.html();//$text.html()和$(this).html()有區別var timer setInterval(function() {//substr(index, …

ES6-7 - 箭頭函數的實質、箭頭函數的使用場景

箭頭函數返回對象 // 這種情況要要用(),否則會將對象的{}解釋為塊 const fn (a, b) > ({a:1, b:2})箭頭函數的特點 this指向由外層函數的作用域來決定&#xff0c;它本身沒有this&#xff0c;不能通過call、apply、bind改變不能作為構造函數使用不可以使用arguments對象&…

mybatis比hibernate處理速度快的原因

mybatis:是面向結果集的。當要展示的頁面需要幾個字段時&#xff0c;springmvc會提供這幾個字段并將其拼接成結果集&#xff0c;在轉化為相應的對象。 hibernate&#xff1a;是面向對象的。要展示的頁面需要某些字段時&#xff0c;會將所有字段都查出來&#xff0c;在轉化為相應…

zabbix 從入門到精通

https://www.cnblogs.com/clsn/p/7885990.html 轉載于:https://www.cnblogs.com/learningJAVA/p/8376589.html

javasript --- 一個日期規范(x秒前,x分前...)

Time函數(通俗易懂,自己根據實際需求修改吧- -) // time.js var Time {// 獲取當前時間戳getUnix: function () {var date new Date();return date.getTime();},// 獲取今天0點0分0秒的時間戳getTodayUnix: function () {var date new Date();date.setHours(0);date.setMin…

ES6-8 - 函數名/對象拓展、描述符、getter/setter

函數名 有兩種特殊情況&#xff1a;bind方法創造的函數&#xff0c;name屬性返回bound加上原函數的名字&#xff1b;Function構造函數創造的函數&#xff0c;name屬性返回anonymous。 bind函數名 // 以bound開頭 function foo() { } const fnName foo.bind().name console.lo…