ES6學習筆記——let和const

let和const命令

let

ES6新增了變量let來解決之前塊級作用域的問題蚯窥。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

第一組代碼中的var是全局的仇穗,所有的i都指向一個i腮郊,所以會是10狱庇,但是在第二組代碼中宁赤。i由let聲明舀透,只在塊級作用域里有效,所以輸出了6决左。

對于for循環(huán)愕够,有特別之處,設置循環(huán)的那部分是父作用域佛猛,而循環(huán)體內部是單獨的子作用域惑芭。

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

由代碼可知,兩個i不一樣

不存在變量提升

使用var會導致變量提升继找,變量在聲明前被使用遂跟,不會報錯,只會輸出undefined婴渡。但是使用let之后再聲明之前使用變量會直接報錯幻锁。

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

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

暫時性死區(qū)(TDZ)

如果你在一個塊級作用域中使用了let,它所聲明的變量就在這個區(qū)域內不受外部的影響缩搅。

var tmp = 123;

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

在該塊級作用域中,tmp使用了let就被綁死了触幼,在該區(qū)域未聲明tmp之前使用tmp就會報錯硼瓣,而跟全局的tmp沒有什么關系。

ES6明確規(guī)定,如果區(qū)塊中存在let和const命令堂鲤,這個區(qū)塊對這些命令聲明的變量亿傅,從一開始就形成了封閉作用域。凡是在聲明之前就使用這些變量瘟栖,就會報錯葵擎。

總之,在代碼塊內半哟,使用let命令聲明變量之前酬滤,該變量都是不可用的。這在語法上寓涨,稱為“暫時性死區(qū)”(temporal dead zone盯串,簡稱 TDZ)。

這個特性的出現(xiàn)戒良,導致typeof操作不是百分之百安全的了体捏。

# 現(xiàn)在
typeof x; // ReferenceError
let x;

# 之前
typeof x; // "undefined"
var x;

上面代碼中,變量x使用let命令聲明糯崎,所以在聲明之前几缭,都屬于x的“死區(qū)”,只要用到該變量就會報錯沃呢。因此年栓,typeof運行時就會拋出一個ReferenceError。

作為比較樟插,如果一個變量根本沒有被聲明韵洋,使用typeof反而不會報錯。

ES6 規(guī)定暫時性死區(qū)和let黄锤、const語句不出現(xiàn)變量提升搪缨,主要是為了減少運行時錯誤,防止在變量聲明前就使用這個變量鸵熟,從而導致意料之外的行為副编。這樣的錯誤在 ES5 是很常見的,現(xiàn)在有了這種規(guī)定流强,避免此類錯誤就很容易了痹届。

總之,暫時性死區(qū)的本質就是打月,只要一進入當前作用域队腐,所要使用的變量就已經存在了,但是不可獲取奏篙,只有等到聲明變量的那一行代碼出現(xiàn)柴淘,才可以獲取和使用該變量迫淹。

不允許重復聲明

let不允許在相同作用域內,重復聲明同一個變量为严。

塊級作用域

let實際是位js新增了塊級作用域敛熬。

  • 允許塊級作用域的任意嵌套
  • 外層作用域無法讀取內層作用域的變量
  • 內層作用域可以定義外層作用域的同名變量
  • 塊級作用域的出現(xiàn),實際上使得獲得廣泛應用的立即執(zhí)行函數(shù)表達式(IIFE)不再必要了

塊級作用域和函數(shù)聲明

ES5中第股,以下情況是非法的:

// 情況一
if (true) {
  function f() {}
}

// 情況二
try {
  function f() {}
} catch(e) {
  // ...
}

但是应民,瀏覽器沒有遵守這個規(guī)定,為了兼容以前的舊代碼夕吻,還是支持在塊級作用域之中聲明函數(shù)诲锹,因此上面兩種情況實際都能運行,不會報錯梭冠。

ES6 引入了塊級作用域辕狰,明確允許在塊級作用域之中聲明函數(shù)。ES6 規(guī)定控漠,塊級作用域之中蔓倍,函數(shù)聲明語句的行為類似于let,在塊級作用域之外不可引用盐捷。

考慮到環(huán)境導致的行為差異太大偶翅,應該避免在塊級作用域內聲明函數(shù)。如果確實需要碉渡,也應該寫成函數(shù)表達式聚谁,而不是函數(shù)聲明語句。

// 函數(shù)聲明語句
{
  let a = 'secret';
  function f() {
    return a;
  }
}

// 函數(shù)表達式
{
  let a = 'secret';
  let f = function () {
    return a;
  };
}

另外滞诺,還有一個需要注意的地方形导。ES6 的塊級作用域允許聲明函數(shù)的規(guī)則,只在使用大括號的情況下成立习霹,如果沒有使用大括號朵耕,就會報錯。

const

const聲明一個只讀的常量淋叶。一旦聲明阎曹,常量的值就不能改變了。const聲明的變量不得改變值煞檩,這意味著处嫌,const一旦聲明變量,就必須立即初始化斟湃,不能留到以后賦值熏迹,如果你只聲明而不賦值,就會發(fā)生錯誤凝赛。

const聲明的常量也存在暫時性死區(qū)注暗,只能在聲明的位置后面使用厨剪;也不能重復聲明。

本質

const實際上保證的友存,并不是變量的值不得改動,而是指向的內存地址不能改動陶衅。這邊就會涉及到說屡立,把對象變成const的,那么只能保證指向對象的指針是不變的搀军,至于它的數(shù)據(jù)結構是不是可變是不可以空數(shù)字的膨俐,所以要很小心。

const foo = {};

// 為 foo 添加一個屬性罩句,可以成功
foo.prop = 123;
foo.prop // 123

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

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

如果你真的想把對象鎖起來,可以使用Object.freeze方法门烂。但是只在嚴格模式下會報錯乳愉,常規(guī)模式下,只是不起作用屯远。

除了將對象本身凍結蔓姚,對象的屬性也應該凍結。下面是一個將對象徹底凍結的函數(shù):

var constantize = (obj) => {
  Object.freeze(obj);
  Object.keys(obj).forEach( (key, i) => {
    if ( typeof obj[key] === 'object' ) {
      constantize( obj[key] );
    }
  });
};

頂層對象的屬性

頂層對象的屬性與全局變量掛鉤慨丐,被認為是JavaScript語言最大的設計敗筆之一坡脐。這樣的設計帶來了幾個很大的問題,首先是沒法在編譯時就報出變量未聲明的錯誤房揭,只有運行時才能知道(因為全局變量可能是頂層對象的屬性創(chuàng)造的备闲,而屬性的創(chuàng)造是動態(tài)的);其次捅暴,程序員很容易不知不覺地就創(chuàng)建了全局變量(比如打字出錯)恬砂;最后,頂層對象的屬性是到處可以讀寫的伶唯,這非常不利于模塊化編程觉既。另一方面,window對象有實體含義乳幸,指的是瀏覽器的窗口對象瞪讼,頂層對象是一個有實體含義的對象,也是不合適的粹断。

ES6為了改變這一點符欠,一方面規(guī)定,為了保持兼容性瓶埋,var命令和function命令聲明的全局變量希柿,依舊是頂層對象的屬性诊沪;另一方面規(guī)定,let命令曾撤、const命令端姚、class命令聲明的全局變量,不屬于頂層對象的屬性挤悉。也就是說渐裸,從ES6開始,全局變量將逐步與頂層對象的屬性脫鉤装悲。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末昏鹃,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子诀诊,更是在濱河造成了極大的恐慌洞渤,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,755評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件属瓣,死亡現(xiàn)場離奇詭異载迄,居然都是意外死亡,警方通過查閱死者的電腦和手機抡蛙,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,305評論 3 395
  • 文/潘曉璐 我一進店門宪巨,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人溜畅,你說我怎么就攤上這事捏卓。” “怎么了慈格?”我有些...
    開封第一講書人閱讀 165,138評論 0 355
  • 文/不壞的土叔 我叫張陵怠晴,是天一觀的道長。 經常有香客問我浴捆,道長蒜田,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,791評論 1 295
  • 正文 為了忘掉前任选泻,我火速辦了婚禮冲粤,結果婚禮上,老公的妹妹穿的比我還像新娘页眯。我一直安慰自己梯捕,他們只是感情好,可當我...
    茶點故事閱讀 67,794評論 6 392
  • 文/花漫 我一把揭開白布窝撵。 她就那樣靜靜地躺著傀顾,像睡著了一般。 火紅的嫁衣襯著肌膚如雪碌奉。 梳的紋絲不亂的頭發(fā)上短曾,一...
    開封第一講書人閱讀 51,631評論 1 305
  • 那天寒砖,我揣著相機與錄音,去河邊找鬼嫉拐。 笑死哩都,一個胖子當著我的面吹牛,可吹牛的內容都是我干的婉徘。 我是一名探鬼主播茅逮,決...
    沈念sama閱讀 40,362評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼判哥!你這毒婦竟也來了?” 一聲冷哼從身側響起碉考,我...
    開封第一講書人閱讀 39,264評論 0 276
  • 序言:老撾萬榮一對情侶失蹤塌计,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后侯谁,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體锌仅,經...
    沈念sama閱讀 45,724評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,900評論 3 336
  • 正文 我和宋清朗相戀三年墙贱,在試婚紗的時候發(fā)現(xiàn)自己被綠了热芹。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,040評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡惨撇,死狀恐怖伊脓,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情魁衙,我是刑警寧澤报腔,帶...
    沈念sama閱讀 35,742評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站剖淀,受9級特大地震影響纯蛾,放射性物質發(fā)生泄漏。R本人自食惡果不足惜纵隔,卻給世界環(huán)境...
    茶點故事閱讀 41,364評論 3 330
  • 文/蒙蒙 一翻诉、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧捌刮,春花似錦碰煌、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,944評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至棚蓄,卻和暖如春堕扶,著一層夾襖步出監(jiān)牢的瞬間碍脏,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,060評論 1 270
  • 我被黑心中介騙來泰國打工稍算, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留典尾,地道東北人。 一個月前我還...
    沈念sama閱讀 48,247評論 3 371
  • 正文 我出身青樓糊探,卻偏偏與公主長得像钾埂,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子科平,可洞房花燭夜當晚...
    茶點故事閱讀 44,979評論 2 355

推薦閱讀更多精彩內容