【ES6基礎】const介紹

在ES6以前,JavaScript被其餘編程語言詬病沒有定義常量的能力,甚至在大多數企業的開發文檔中,對於常量的定義都使用var。通常常常會使用大寫字母和下劃線組成的變量名進行規範約束。固然這種妥協的「常量」是隨時可變的。例如如下代碼:javascript

var MAX_COUNT=0;
MAX_COUNT=1 //WARNING複製代碼

好在E6引入了const,讓JavaScript得到了真正的定義常量的能力,接下來小編將和你們一塊兒學習const,經過本篇文章,你將學到如下內容:前端

  • const介紹
  • 可變的對象變量
  • 如何讓對象的屬性不可變?
  • 做用域範圍
  • 如何選擇var/let/const

本篇文章閱讀時間預計10分鐘java

const介紹

使用const語法建立變量,一旦建立初始化,咱們就不能改變他們的值,所以這就稱爲常量。若是你嘗試改變一個const變量,則會拋出異常。此外,若是你使用const只聲明變量,不進行初始化,也會拋出異常。如如下代碼,試圖改變一個常量,引擎就會拋出異常:編程

const pi = 3.141;
pi = 4; // not possible in this universe, or in other terms, 
        // throws Read-only error複製代碼

因爲ES6能夠爲程序工程化提供內存安全的優點,即是由於const定義常量的原理是阻隔變量所對應的內存地址被改變。數組

變量與內存之間的關係由三個部分組成:變量名、內存綁定和內存地址。以下圖所示:安全

ES6在對變量的引用進行讀取時,會從該變量當前所對應的內存地址所指向內存空間中讀取內容。當變量改變時,引擎會從新從內存分配一個新的內存空間以存儲新值,並將新的內存地址與變量進行綁定。const的原理即是在變量名與內存地址之間創建不可變的綁定,當嘗試從新分配新的內存空間時,引擎便會拋出異常。bash

在某些狀況,並不是值不可變。以V8引擎爲例,如字符串、數字、布爾值、undined等值類型只佔用一組內存空間的,這些類型的值再內存空間中是連續的、不可拆分的。而對於對象、數組等稀疏的引用類型值,因爲屬性值是能夠變化的,因此爲了最快地進行內存調度,當對象的屬性被改變或添加了新的屬性時,都須要從新計算內存地址偏移值。所以使用const定義對象時,因爲所建立的內存只綁定一處的,因此默認狀況下對象這種由若干內存空間片斷組成的值並不會所有被鎖定,所以使用const定義對象時,對象的屬性值是可變的。微信

可變的對象變量

上一小節咱們說起到,當咱們使用const定義對象時,因爲對象是引用類型值,而非對象自己,所以更改對象的屬性是可行的,從新更改整個對象變量會拋出異常,以下段代碼所示:編程語言

const a = {
  name: "Mehul"
};
console.log(a.name);
a.name = "Mohan";
console.log(a.name);
a = {}; //throws read-only exception複製代碼

上述代碼輸出post

Mehul
Mohan
<Error thrown>複製代碼

在此示中,a變量是引用值類型,對象地址是不能改變的,可是這個對象自己的屬性是能夠改變的。所以,當咱們嘗試將頂一個對象分配給a變量時,引擎就會拋出異常。

如何讓對象的屬性值不可變呢?

上一小節,咱們瞭解了,使用const定義變量時,變量的屬性是能夠更改的,如何讓其不能更改呢,其實只要配合ES5中的Object.freeze()方法,即可以得到一個第一層屬性(首層)不可變的對象。若是第一層屬性中存在對象嵌套,嵌套對象的屬性仍然是能夠改變的。以下段代碼所示:

const ob1 = {
   prop1 : 1,
    prop2 : {
        prop2_1 : 2 
    }
};
Object.freeze( ob1 );
ob1.prop1 = 4; // (frozen) ob1.prop1 is not modified 
ob1.prop2.prop2_1 = 4; // (frozen) modified, because ob1.prop2.prop2_1 is nested
ob1.prop2 = 4; // (frozen) not modified, bar is a key of obj1
ob1 = {}; // (const) ob2 not redeclared (used const)複製代碼

如何實現全部層級的屬性不可變呢?咱們能夠用遞歸的方式調用Object.freeze進行實現,以下段代碼所示(代碼來源MDN):

function deepFreeze(object) {

  // Retrieve the property names defined on object
  var propNames = Object.getOwnPropertyNames(object);

  // Freeze properties before freezing self
  
  for (let name of propNames) {
    let value = object[name];

    object[name] = value && typeof value === "object" ? 
      deepFreeze(value) : value;
  }

  return Object.freeze(object);
}

var obj2 = {
  internal: {
    a: null
  }
};

deepFreeze(obj2);

obj2.internal.a = 'anotherValue'; // fails silently in non-strict mode
obj2.internal.a; // null複製代碼

做用域範圍

關於做用域的概念,小編在這篇文章《【ES基礎】let和做用域》已經介紹過了,不清楚的能夠點擊連接進行查看,const和let同樣,也是塊做用域變量,他們遵循相同的做用域規則,以下段代碼所示:

const a = 12; // accessible globally
function myFunction() {
  console.log(a);
  const b = 13; // accessible throughout function
  if(true) {
    const c = 14; // accessible throughout the "if" statement
    console.log(b);
  }
console.log(c);
}
myFunction();複製代碼

上述代碼輸出

12
13
ReferenceError Exception複製代碼

如何選擇var/let/const

從ES6引入let的語法,設計的初衷即是替代var。從工程化的角度來講,咱們應從ES6後聽從如下三原則:

  1. 通常狀況下,使用const在定義常量。
  2. 只有明確值會被改變時,咱們才使用let定義變量。
  3. 再也不使用var。

結束語

今天的內容就介紹到這裏,爲了更好的使用ES6,咱們應該儘快適應使用const定義常量,使用let定義變量。

更多精彩內容,請微信關注」前端達人」公衆號!

相關文章
相關標籤/搜索