JS 使用const聲明常量的本質(不少人都有誤解)

在咱們使用const聲明常量時,總認爲值一旦聲明就不可改變,實際上是有誤解的;數組

剛在看ES6標準文檔時,仔細閱讀了const的解析,恍然大悟的感受,分享給你們。數據結構

本質

const實際上保證的,並非變量的值不得改動,而是變量指向的那個內存地址不得改動。對於簡單類型的數據(數值、字符串、布爾值),值就保存在變量指向的那個內存地址,所以等同於常量。函數

但對於複合類型的數據(主要是對象和數組),變量指向的內存地址,保存的只是一個指針,const只能保證這個指針是固定的,至於它指向的數據結構是否是可變的,就徹底不能控制了。所以,將一個對象聲明爲常量必須很是當心。spa

const foo = {};

// 爲 foo 添加一個屬性,能夠成功
foo.prop = 123;
foo.prop // 123

// 將 foo 指向另外一個對象,就會報錯
foo = {}; // TypeError: "foo" is read-only

上面代碼中,常量foo儲存的是一個地址,這個地址指向一個對象。不可變的只是這個地址,即不能把foo指向另外一個地址,但對象自己是可變的,因此依然能夠爲其添加新屬性。指針

下面是另外一個例子。code

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

上面代碼中,常量a是一個數組,這個數組自己是可寫的,可是若是將另外一個數組賦值給a,就會報錯。對象

若是真的想將對象凍結,應該使用Object.freeze方法。blog

const foo = Object.freeze({});

// 常規模式時,下面一行不起做用;
// 嚴格模式時,該行會報錯
foo.prop = 123;

上面代碼中,常量foo指向一個凍結的對象,因此添加新屬性不起做用,嚴格模式時還會報錯。內存

除了將對象自己凍結,對象的屬性也應該凍結。下面是一個將對象完全凍結的函數。文檔

var constantize = (obj) => {
  Object.freeze(obj);
  Object.keys(obj).forEach( (key, i) => {
    if ( typeof obj[key] === 'object' ) {
      constantize( obj[key] );
    }
  });
};
相關文章
相關標籤/搜索