let 和 const 命令

1 let

ES6 新增了let命令白粉,用來(lái)聲明變量传泊。它的用法類似于var,但是所聲明的變量鸭巴,只在let命令所在的代碼塊內(nèi)有效眷细。

{
  let a = 10;
  var b = 1;
}

a // ReferenceError: a is not defined.
b // 1

另外,for循環(huán)還有一個(gè)特別之處鹃祖,就是設(shè)置循環(huán)變量的那部分是一個(gè)父作用域溪椎,而循環(huán)體內(nèi)部是一個(gè)單獨(dú)的子作用域。

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

不存在變量提升

let命令改變了語(yǔ)法行為惯豆,它所聲明的變量一定要在聲明后使用池磁,否則報(bào)錯(cuò)。

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

// let 的情況
console.log(bar); // 報(bào)錯(cuò)ReferenceError
let bar = 2;

暫時(shí)性死區(qū)

只要塊級(jí)作用域內(nèi)存在let命令楷兽,它所聲明的變量就“綁定”(binding)這個(gè)區(qū)域地熄,不再受外部的影響。

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

上面代碼中芯杀,存在全局變量tmp端考,但是塊級(jí)作用域內(nèi)let又聲明了一個(gè)局部變量tmp雅潭,導(dǎo)致后者綁定這個(gè)塊級(jí)作用域,所以在let聲明變量前却特,對(duì)tmp賦值會(huì)報(bào)錯(cuò)扶供。

ES6明確規(guī)定,如果區(qū)塊中存在let和const命令裂明,這個(gè)區(qū)塊對(duì)這些命令聲明的變量椿浓,從一開始就形成了封閉作用域。凡是在聲明之前就使用這些變量闽晦,就會(huì)報(bào)錯(cuò)扳碍。

總之,在代碼塊內(nèi)仙蛉,使用let命令聲明變量之前笋敞,該變量都是不可用的。這在語(yǔ)法上荠瘪,稱為“暫時(shí)性死區(qū)”(temporal dead zone夯巷,簡(jiǎn)稱 TDZ)。
“暫時(shí)性死區(qū)”也意味著typeof不再是一個(gè)百分之百安全的操作哀墓。

總之趁餐,暫時(shí)性死區(qū)的本質(zhì)就是,只要一進(jìn)入當(dāng)前作用域麸祷,所要使用的變量就已經(jīng)存在了澎怒,但是不可獲取,只有等到聲明變量的那一行代碼出現(xiàn)阶牍,才可以獲取和使用該變量。

不允許重復(fù)聲明

let不允許在相同作用域內(nèi)星瘾,重復(fù)聲明同一個(gè)變量走孽。
因此,不能在函數(shù)內(nèi)部重新聲明參數(shù)琳状。

function func(arg) {
  let arg; // 報(bào)錯(cuò)
}

function func(arg) {
  {
    let arg; // 不報(bào)錯(cuò)
  }
}

2 塊級(jí)作用域

ES5 只有全局作用域和函數(shù)作用域磕瓷,沒有塊級(jí)作用域,這帶來(lái)很多不合理的場(chǎng)景念逞。

第一種場(chǎng)景困食,內(nèi)層變量可能會(huì)覆蓋外層變量。

var tmp = new Date();
function f() {
  console.log(tmp);
  if (false) {
    var tmp = 'hello world';
  }
}

f(); // undefined

上面代碼的原意是翎承,if代碼塊的外部使用外層的tmp變量硕盹,內(nèi)部使用內(nèi)層的tmp變量。但是叨咖,函數(shù)f執(zhí)行后瘩例,輸出結(jié)果為undefined啊胶,原因在于變量提升,導(dǎo)致內(nèi)層的tmp變量覆蓋了外層的tmp變量垛贤。

ES6 的塊級(jí)作用域

let實(shí)際上為 JavaScript 新增了塊級(jí)作用域焰坪。

function f1() {
  let n = 5;
  if (true) {
    let n = 10;
    console.log(n); //10
  }
  console.log(n); // 5
}

塊級(jí)作用域不能向父作用域讀取同名變量,塊級(jí)作用域的出現(xiàn),實(shí)際上使得獲得廣泛應(yīng)用的立即執(zhí)行函數(shù)表達(dá)式(IIFE)不再必要了聘惦。

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

// 塊級(jí)作用域?qū)懛?{
  let tmp = ...;
  ...
}

塊級(jí)作用域與函數(shù)聲明

ES5 規(guī)定某饰,函數(shù)只能在頂層作用域和函數(shù)作用域之中聲明,不能在塊級(jí)作用域聲明善绎。
但是ES6 引入了塊級(jí)作用域黔漂,明確允許在塊級(jí)作用域之中聲明函數(shù)。ES6 規(guī)定涂邀,塊級(jí)作用域之中瘟仿,函數(shù)聲明語(yǔ)句的行為類似于let,在塊級(jí)作用域之外不可引用比勉。
ES6在[附錄B]里面規(guī)定劳较,瀏覽器的實(shí)現(xiàn)可以不遵守上面的規(guī)定,有自己的[行為方式]

允許在塊級(jí)作用域內(nèi)聲明函數(shù)浩聋。
函數(shù)聲明類似于var观蜗,即會(huì)提升到全局作用域或函數(shù)作用域的頭部。
同時(shí)衣洁,函數(shù)聲明還會(huì)提升到所在的塊級(jí)作用域的頭部墓捻。
注意,上面三條規(guī)則只對(duì) ES6 的瀏覽器實(shí)現(xiàn)有效坊夫,其他環(huán)境的實(shí)現(xiàn)不用遵守砖第,還是將塊級(jí)作用域的函數(shù)聲明當(dāng)作let處理。
根據(jù)這三條規(guī)則环凿,在瀏覽器的 ES6 環(huán)境中梧兼,塊級(jí)作用域內(nèi)聲明的函數(shù),行為類似于var聲明的變量智听。

考慮到環(huán)境導(dǎo)致的行為差異太大羽杰,應(yīng)該避免在塊級(jí)作用域內(nèi)聲明函數(shù)。如果確實(shí)需要到推,也應(yīng)該寫成函數(shù)表達(dá)式考赛,而不是函數(shù)聲明語(yǔ)句。

do 表達(dá)式

本質(zhì)上莉测,塊級(jí)作用域是一個(gè)語(yǔ)句颜骤,將多個(gè)操作封裝在一起,沒有返回值悔雹。

{
  let t = f();
  t = t * t + 1;
}

上面代碼中复哆,塊級(jí)作用域?qū)蓚€(gè)語(yǔ)句封裝在一起欣喧。但是,在塊級(jí)作用域以外梯找,沒有辦法得到t
的值唆阿,因?yàn)閴K級(jí)作用域不返回值,除非t
是全局變量锈锤。
現(xiàn)在有一個(gè)[提案]驯鳖,使得塊級(jí)作用域可以變?yōu)楸磉_(dá)式,也就是說(shuō)可以返回值久免,辦法就是在塊級(jí)作用域之前加上do浅辙,使它變?yōu)閐o表達(dá)式。

let x = do {
  let t = f();
  t * t + 1;
};

3 const 命令

const聲明一個(gè)只讀的常量阎姥。一旦聲明记舆,常量的值就不能改變。

const聲明的變量不得改變值呼巴,這意味著泽腮,const一旦聲明變量,就必須立即初始化衣赶,不能留到以后賦值诊赊。

對(duì)于const來(lái)說(shuō),只聲明不賦值府瞄,就會(huì)報(bào)錯(cuò)碧磅。

const的作用域與let命令相同:只在聲明所在的塊級(jí)作用域內(nèi)有效。

const命令聲明的常量也是不提升遵馆,同樣存在暫時(shí)性死區(qū)鲸郊,只能在聲明的位置后面使用。

const聲明的常量货邓,也與let一樣不可重復(fù)聲明严望。

本質(zhì):const實(shí)際上保證的,并不是變量的值不得改動(dòng)逻恐,而是變量指向的那個(gè)內(nèi)存地址不得改動(dòng)。對(duì)于簡(jiǎn)單類型的數(shù)據(jù)(數(shù)值峻黍、字符串复隆、布爾值),值就保存在變量指向的那個(gè)內(nèi)存地址姆涩,因此等同于常量挽拂。但對(duì)于復(fù)合類型的數(shù)據(jù)(主要是對(duì)象和數(shù)組),變量指向的內(nèi)存地址骨饿,保存的只是一個(gè)指針亏栈,const只能保證這個(gè)指針是固定的台腥,至于它指向的數(shù)據(jù)結(jié)構(gòu)是不是可變的,就完全不能控制了绒北。因此黎侈,將一個(gè)對(duì)象聲明為常量必須非常小心。
例如:給const申明的變量賦值為一個(gè)空對(duì)象,對(duì)象地址不能改變,但可以利用對(duì)象的動(dòng)態(tài)屬性給對(duì)象添加屬性,const變量的值也就變相改變了
如果真的想將對(duì)象凍結(jié)闷游,應(yīng)該使用Object.freeze方法峻汉。

const foo = Object.freeze({});

// 常規(guī)模式時(shí),下面一行不起作用脐往;
// 嚴(yán)格模式時(shí)休吠,該行會(huì)報(bào)錯(cuò)
foo.prop = 123;

除了將對(duì)象本身凍結(jié),對(duì)象的屬性也應(yīng)該凍結(jié)业簿。下面是一個(gè)將對(duì)象徹底凍結(jié)的函數(shù)瘤礁。

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

頂層對(duì)象的屬性

ES6為了改變這一點(diǎn),一方面規(guī)定梅尤,為了保持兼容性柜思,var命令和function命令聲明的全局變量,依舊是頂層對(duì)象的屬性克饶;另一方面規(guī)定酝蜒,let命令、const命令矾湃、class命令聲明的全局變量亡脑,不屬于頂層對(duì)象的屬性。也就是說(shuō)邀跃,從ES6開始霉咨,全局變量將逐步與頂層對(duì)象的屬性脫鉤。

var a = 1;
// 如果在Node的REPL環(huán)境拍屑,可以寫成global.a
// 或者采用通用方法途戒,寫成this.a
window.a // 1

let b = 1;
window.b // undefined

global 對(duì)象

ES5 的頂層對(duì)象,本身也是一個(gè)問題僵驰,因?yàn)樗诟鞣N實(shí)現(xiàn)里面是不統(tǒng)一的喷斋。

1 瀏覽器里面,頂層對(duì)象是window蒜茴,但 Node 和 Web Worker 沒有window星爪。
2 瀏覽器和 Web Worker 里面,self也指向頂層對(duì)象粉私,但是 Node 沒有self顽腾。
3 Node 里面,頂層對(duì)象是global诺核,但其他環(huán)境都不支持抄肖。
綜上所述久信,很難找到一種方法,可以在所有情況下漓摩,都取到頂層對(duì)象裙士。下面是兩種勉強(qiáng)可以使用的方法:

// 方法一
(typeof window !== 'undefined'
   ? window
   : (typeof process === 'object' &&
      typeof require === 'function' &&
      typeof global === 'object')
     ? global
     : this);

// 方法二
var getGlobal = function () {
  if (typeof self !== 'undefined') { return self; }
  if (typeof window !== 'undefined') { return window; }
  if (typeof global !== 'undefined') { return global; }
  throw new Error('unable to locate global object');
};

墊片庫(kù)system.global
模擬了這個(gè)提案,可以在所有環(huán)境拿到global幌甘。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末潮售,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子锅风,更是在濱河造成了極大的恐慌酥诽,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,639評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件皱埠,死亡現(xiàn)場(chǎng)離奇詭異肮帐,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)边器,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,277評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門训枢,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人忘巧,你說(shuō)我怎么就攤上這事恒界。” “怎么了砚嘴?”我有些...
    開封第一講書人閱讀 157,221評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵十酣,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我际长,道長(zhǎng)耸采,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,474評(píng)論 1 283
  • 正文 為了忘掉前任工育,我火速辦了婚禮虾宇,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘如绸。我一直安慰自己嘱朽,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,570評(píng)論 6 386
  • 文/花漫 我一把揭開白布怔接。 她就那樣靜靜地躺著燥翅,像睡著了一般。 火紅的嫁衣襯著肌膚如雪蜕提。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,816評(píng)論 1 290
  • 那天靶端,我揣著相機(jī)與錄音谎势,去河邊找鬼凛膏。 笑死,一個(gè)胖子當(dāng)著我的面吹牛脏榆,可吹牛的內(nèi)容都是我干的猖毫。 我是一名探鬼主播,決...
    沈念sama閱讀 38,957評(píng)論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼须喂,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼吁断!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起坞生,我...
    開封第一講書人閱讀 37,718評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤仔役,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后是己,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體又兵,經(jīng)...
    沈念sama閱讀 44,176評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,511評(píng)論 2 327
  • 正文 我和宋清朗相戀三年卒废,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了沛厨。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,646評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡摔认,死狀恐怖逆皮,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情参袱,我是刑警寧澤电谣,帶...
    沈念sama閱讀 34,322評(píng)論 4 330
  • 正文 年R本政府宣布,位于F島的核電站蓖柔,受9級(jí)特大地震影響辰企,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜况鸣,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,934評(píng)論 3 313
  • 文/蒙蒙 一牢贸、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧镐捧,春花似錦潜索、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,755評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至列牺,卻和暖如春整陌,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,987評(píng)論 1 266
  • 我被黑心中介騙來(lái)泰國(guó)打工泌辫, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留随夸,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,358評(píng)論 2 360
  • 正文 我出身青樓震放,卻偏偏與公主長(zhǎng)得像宾毒,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子殿遂,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,514評(píng)論 2 348

推薦閱讀更多精彩內(nèi)容

  • let 命令 塊級(jí)作用域 const 命令 頂層對(duì)象的屬性 global 對(duì)象 let 命令 基本用法 ES6 新...
    嘉奇呦_nice閱讀 1,624評(píng)論 0 2
  • let 命令 塊級(jí)作用域 const 命令 頂層對(duì)象的屬性 global 對(duì)象 let 命令 基本用法 ES6 新...
    卞卞村長(zhǎng)L閱讀 589評(píng)論 0 0
  • let 和 const 命令 let 命令 塊級(jí)作用域 const 命令 頂層對(duì)象的屬性 gl...
    安小明閱讀 980評(píng)論 0 0
  • 1.let命令 基本用法 ES6 新增了let命令诈铛,用來(lái)聲明變量。它的用法類似于var墨礁,但是所聲明的變量幢竹,只在le...
    angelwgh閱讀 283評(píng)論 0 0
  • 我知道,你會(huì)擔(dān)心饵溅。 我會(huì)勇敢地去面對(duì)妨退,好好地去處理。
    減肥的女孩閱讀 205評(píng)論 0 1