學習記錄1.ES6入門-var、let、const和塊級作用域

  今天又開始學習ES6,光看會混淆,於是決定做筆記可以疏通一下自己的思路,又便於以後的鞏固,與大家共勉😉😉。

一、var、let和const的區別與詳解

  ES5 只有兩種聲明變量的方法:var命令和function命令。ES6 除了添加let和const命令,還有另外兩種聲明變量的方法:import命令和class命令。所以,ES6 一共有 6 種聲明變量的方法。
  今天我只學習了var、let和const,所以只記錄這三個。

  1. var、let聲明變量,const聲明常量
  2. var有變量提升,且當var是全局變量時,屬於頂層對象屬性;let、const不存在變量提升,不可重複聲明變量,聲明的變量只在它所在的代碼塊有效,不屬於頂層對象屬性

舉例:
let vs var:

(1) let變量只在他所在的代碼塊內有有效

{
 let a = 10;
 var b = 1;
}
a // ReferenceError: a is not defined.
b //1

(2)for循環的計數器,就很合適使用let命令。

var a = [];
for (var i = 0; i < 10; i++) {
 a[i] = function () {
   console.log(i);
 };
}

a[6](); // 10
var a = [];
for (let i = 0; i < 10; i++) {
 a[i] = function () {
   console.log(i);
 };
}
a[6](); // 6

解釋:
  在第一個中,變量i是var變量聲明的,i在全局範圍內都有效,也就是說,全局只有一個變量i,只不過i是動態變化的,每循環一次,i的值就變一次。所有數組a的成員裏面的i,指向的都是同一個i,導致運行時輸出的是最後一輪的i的值,也就是 10。
  在第二個中,變量i是let聲明的,當前的i只在本輪循環有效,也就是說,每次循環的i都是新的變量。Javascript內部引擎會記住上一輪i的值,初始化本輪i的值,就在上輪的基礎上進行計算。

(3)循環變量的那部分是一個父作用域,而循環體內部是一個單獨的子作用域

for (let i = 0; i < 3; i++) {
  console.log(i);
}
// 0 1 2
for (let i = 0; i < 3; i++) {
  let i = 'abc';
  console.log(i);
}
//?

  大家覺得打印出來的結果會是什麼?0,1,2 還是 三個abc
  答案是,輸出了三次 abc.這表明函數內部的變量i與循環變量i不在同一個作用域,有各自單獨的作用域

(4)不存在變量提升
  var命令會發生“變量提升”現象,即變量可以在聲明之前使用,值爲undefined
let命令改變了語法行爲,它所聲明的變量一定要在聲明後使用,否則報錯。

// var 的情況
console.log(foo); // 輸出undefined
var foo = 2;

// let 的情況
console.log(bar); // 報錯ReferenceError
let bar = 2;

(5)暫時性死區

var tmp = 123;

if (true) {
  tmp = 'abc'; // ReferenceError
  let tmp;
}

解釋:
  雖然var聲明瞭全局變量 temp,但是在代碼塊內又聲明瞭let型的局部變量temp,let型的局部變量temp綁定了這個代碼塊,導致在let聲明變量前對temp賦值會報錯。

(6)不允許重複聲明

// 報錯
function func() {
  let a = 10;
  var a = 1;
}

// 報錯
function func() {
  let a = 10;
  let a = 1;
}
----------------------------------------
function func(arg) {
  let arg;
}
func() // 報錯

function func(arg) {
  {
    let arg;
  }
}
func() // 不報錯

const:
(1)const聲明一個只讀的常量。一旦聲明,常量的值就不能改變。

const PI = 3.1415;
PI // 3.1415

PI = 3;
// TypeError: Assignment to constant variable.

(2)const的作用域與let命令相同:只在聲明所在的塊級作用域內有效。
(3)const命令聲明的常量也是不提升,同樣存在暫時性死區,只能在聲明的位置後面使用
本質:

const實際上保證的,並不是變量的值不得改動,而是變量指向的那個內存地址所保存的數據不得改動。對於簡單類型的數據(數值、字符串、布爾值),值就保存在變量指向的那個內存地址,因此等同於常量。但對於複合類型的數據(主要是對象和數組),變量指向的內存地址,保存的只是一個指向實際數據的指針,const只能保證這個指針是固定的(即總是指向另一個固定的地址),至於它指向的數據結構是不是可變的,就完全不能控制了。因此,將一個對象聲明爲常量必須非常小心。

const a = [];
a.push('Hello'); // 可執行
a.length = 0;    // 可執行
a = ['Dave'];    // 報錯

  聲明瞭數組常量a,這個數組本身是可寫的,但是如果將另一個數組賦值給a就會報錯。

二、頂層對象

(1)頂層對象,在瀏覽器環境指的是window對象,在 Node 指的是global對象。ES5 之中,頂層對象的屬性與全局變量是等價的。
(2)爲了保持兼容性,ES6中,var命令和function命令聲明的全局變量,依舊是頂層對象的屬性;另一方面規定,let命令、const命令、class命令聲明的全局變量,不屬於頂層對象的屬性。也就是說,從 ES6 開始,全局變量將逐步與頂層對象的屬性脫鉤。
(3)在語言標準的層面,引入globalThis作爲頂層對象。也就是說,任何環境下,globalThis都是存在的,都可以從它拿到頂層對象,指向全局環境下的this。

三、塊級作用域

(1)允許塊級作用域的任意嵌套

{{{{
  {let insane = 'Hello World'}
  console.log(insane); // 報錯
}}}};

解釋:
  上面代碼使用了一個五層的塊級作用域,每一層都是一個單獨的作用域。第四層作用域無法讀取第五層作用域的內部變量
(2)內層作用域可以定義外層作用域的同名變量

{{{{
  let insane = 'Hello World';
  {let insane = 'Hello World'}
}}}};

(3)塊級作用域的出現,實際上使得獲得廣泛應用的匿名立即執行函數表達式(匿名 IIFE)不再必要了

// IIFE 寫法
(function () {
  var tmp = ...;
  ...
}());

// 塊級作用域寫法
{
  let tmp = ...;
  ...
}

(4)塊級作用域與函數聲明
1.ES5 規定,函數只能在頂層作用域和函數作用域之中聲明,不能在塊級作用域聲明
2.ES6 規定,塊級作用域之中,函數聲明語句的行爲類似於let,在塊級作用域之外不可引用
3.ES6 的塊級作用域必須有大括號,如果沒有大括號,JavaScript 引擎就認爲不存在塊級作用域

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章