摘要:準(zhǔn)確的說(shuō),之前,不存在語(yǔ)法級(jí)的塊級(jí)作用域支持,開發(fā)者往往以創(chuàng)建一個(gè)立即執(zhí)行的函數(shù)來(lái)隔離外部世界對(duì)函數(shù)內(nèi)部變量的訪問權(quán)。塊級(jí)聲明提供了和標(biāo)識(shí)符,用于聲明塊級(jí)作用域的變量。全局塊作用域和與的另外一個(gè)區(qū)別是它們?cè)谌肿饔糜蛑械男袨椤?/p>
var聲明的提升
先看下面這段代碼:
function getValue(condition) { if(condition) { var value = "blue"; return value; } else { // 此處可訪問變量value, 其值為undefined return null; } // 此處可訪問變量value, 其值為undefined }
如果你不熟悉JavaScript,可能會(huì)認(rèn)為只有當(dāng)condition的值為true時(shí)才會(huì)創(chuàng)建變量value。事實(shí)上,在預(yù)編譯階段,JavaScript引擎會(huì)將上面的函數(shù)修改成下面這樣:
function getValue(condition) { var value; if(condition) { value = "blue"; return value; } else { return null; } }
變量value的聲明被提升至函數(shù)頂部,而初始化操作留在原處執(zhí)行。
再看一段代碼:
for(var i=0;i<10;i++){ } console.log(i); // 10
這段for循環(huán)結(jié)束后,循環(huán)外的i變量并非undefined。同樣也是由于i變量聲明提升所致。
準(zhǔn)確的說(shuō),ES6之前,不存在語(yǔ)法級(jí)的塊級(jí)作用域支持,開發(fā)者往往以創(chuàng)建一個(gè)立即執(zhí)行的函數(shù)來(lái)隔離外部世界對(duì)函數(shù)內(nèi)部變量的訪問權(quán)。
(function(){ ... })()塊級(jí)聲明
ES6提供了let和const標(biāo)識(shí)符,用于聲明塊級(jí)作用域的變量。
塊級(jí)作用域存在于:
函數(shù)內(nèi)部
塊中(字符{和}之間的區(qū)域)
let聲明function getValue(condition) { if(condition) { let value = "blue"; return value; } else { // 變量value在此處不存在 return null; } // 變量value在此處不存在 }禁止重復(fù)聲明
同一作用域內(nèi),不能用let去重復(fù)聲明已聲明過的變量:
var count = 30; let count = 40; // 拋出語(yǔ)法錯(cuò)誤
這樣子是可以的:
var count = 30; // if塊外的變量 if(condition) { let count = 40; // 聲明的是if塊中的新變量 }const聲明
與let聲明的區(qū)別是,const聲明的是常量,其值一旦被設(shè)定后不可更改。因此聲明時(shí)就必須進(jìn)行初始化:
const maxItems = 30; maxItems = 40; // 語(yǔ)法錯(cuò)誤,常量不可修改 const name; // 語(yǔ)法錯(cuò)誤,未初始化const聲明的對(duì)象
const聲明不允許修改綁定,但允許修改值。意味著const聲明對(duì)象后,可以修改該對(duì)象的屬性值。有Java后端經(jīng)驗(yàn)的同學(xué)很容易理解,這就是Java的值傳遞:
const person = { name: "Nicholas" }; person.name = "Greg"; // 可以修改對(duì)象屬性的值 // 拋出語(yǔ)法錯(cuò)誤 person = { // 不允許修改引用 name: "Greg"; };臨時(shí)性死區(qū)(Temporal Dead Zone)
ECMAScript標(biāo)準(zhǔn)并沒有明確提到TDZ,但人們常用它來(lái)描述let和const的不提升效果。
JavaScript引擎在掃碼代碼發(fā)現(xiàn)變量聲明時(shí),要么將它們提升至作用域頂部(遇到var聲明),要么將它們放到TDZ中(遇到let和const聲明)。訪問TDZ中的變量會(huì)觸發(fā)運(yùn)行時(shí)錯(cuò)誤:
if(condition) { console.log(typeof value); // 引用錯(cuò)誤, 不允許訪問TDZ中的變量 let value = "blue"; // 只有執(zhí)行過聲明語(yǔ)句后,變量才從TDZ中移除 }
可見,即便是相對(duì)不易出錯(cuò)的typeof操作符也無(wú)法阻擋引擎拋出錯(cuò)誤。
在let聲明的作用域外對(duì)該變量使用typeof則不會(huì)報(bào)錯(cuò):
console.log(typeof value); // "undefined" if(condition) { let value = "blue"; }
typeof是在聲明變量value的代碼塊外執(zhí)行的,此時(shí)value不在TDZ中。
循環(huán)中的塊級(jí)作用域 在循環(huán)中創(chuàng)建函數(shù)長(zhǎng)久以來(lái),var聲明讓開發(fā)者在循環(huán)中創(chuàng)建函數(shù)變得異常困難,因?yàn)樽兞康搅搜h(huán)之外仍能訪問:
var funcs = []; for(var i=0; i<10; i++) { funcs.push(function(){ console.log(i); }); } funcs.forEach(function(func) { func(); // 輸出10次數(shù)字10 });
不是預(yù)期的輸出0~9,而是輸出10次10。因?yàn)檠h(huán)中的i變量聲明提升到外部了,循環(huán)內(nèi)創(chuàng)建的函數(shù)全部保留了對(duì)相同變量i的引用。
以往,為解決這個(gè)問題,開發(fā)者們往往使用立即調(diào)用函數(shù)表達(dá)式(IIFE):
var funcs = []; for(var i=0; i<10; i++) { funcs.push((function(value) { return function() { console.log(value); } }(i))); } funcs.forEach(function(func) { func(); // 輸出0、然后是1、2,直到9 });
ES6提供的let和const讓我們?cè)僖矡o(wú)需這么折騰了,直接把var換成let就搞定:
var funcs = []; for(let i=0; i<10; i++) { funcs.push(function(){ console.log(i); }); } funcs.forEach(function(func) { func(); // 輸出0、然后是1、2,直到9 });循環(huán)中使用let和const的說(shuō)明
標(biāo)準(zhǔn)的for循環(huán),每次循環(huán)后會(huì)修改變量值,因此必須使用let:
for(let i=0; i<10; i++) {}
ES6的for-in和for-of循環(huán),由于每次迭代不會(huì)修改已有的綁定,因此可以使用const代替:
for(const key in object) {}
let values = [1, 2, 3]; for(const value of values) {}塊級(jí)綁定最佳實(shí)踐
對(duì)JavaScript開發(fā)者而言,直接用let代替var也符合邏輯。這種情況下,只需注意對(duì)需要寫保護(hù)的變量則使用const。隨著更多的開發(fā)者遷移到ES6,另一種做法一日普及,默認(rèn)使用const,只有確實(shí)需要改變變量的值時(shí)使用let。因?yàn)榇蟛糠肿兞康闹翟诔跏蓟蟛粦?yīng)再改變,而變量值預(yù)料之外的改變是很多bug的源頭。這一理念獲得了很多人的支持,你不妨試試。
全局塊作用域let和const與var的另外一個(gè)區(qū)別是它們?cè)谌肿饔糜蛑械男袨?。?dāng)var被用于全局作用域時(shí),它會(huì)創(chuàng)建一個(gè)新的全局變量作為全局對(duì)象(瀏覽器環(huán)境中的window對(duì)象)的屬性。這意味著用var很可能會(huì)無(wú)意中覆蓋一個(gè)已經(jīng)存在的全局變量:
var RegExp = "Hello!"; console.log(window.RegExp); // "Hello!" var ncz = "Hi!"; console.log(window.ncz); //"Hi!"
即使全局對(duì)象RegExp定義在window上,也不能幸免于被var聲明覆蓋。同樣,ncz被定義為一個(gè)全局變量,并且立即成為window的屬性。JavaScript過去一直這樣。
使用let或const則不會(huì):
let RegExp = "Hello!"; console.log(RegExp); // "Hello!" console.log(window.RegExp === RegExp); // false const ncz = "Hi!"; console.log(ncz); // "Hi!" console.log("ncz" in window); // false
如果希望在全局對(duì)象下定義變量,仍然可以用var。這種情況常見于在瀏覽器中跨frame或跨window訪問代碼。
總而言之,跨越到ES6后,大家可以把var忘了。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://m.hztianpu.com/yun/87377.html
摘要:聲明之函數(shù)作用域和全局作用域。塊級(jí)作用域不能重復(fù)聲明臨時(shí)性死區(qū)等特性用來(lái)解決變量存在的種種問題。塊級(jí)作用域終于在外面訪問不到了。一些常量聲明使用聲明的變量名全部大寫。 ES5之前javascript語(yǔ)言只有函數(shù)作用域和全局作用域,使用var來(lái)聲明變量,var聲明的變量還存在變量提升使人困惑不已。我們先來(lái)復(fù)習(xí)一下ES5的var聲明,再對(duì)比學(xué)習(xí)let和const 。 var var聲明之函...
摘要:不允許在相同作用域內(nèi),重復(fù)聲明同一個(gè)變量。如但是在中則不再必要了,我們可以通過塊級(jí)作用域就能夠?qū)崿F(xiàn)本次主要針對(duì)中的變量和塊級(jí)作用域進(jìn)行了梳理學(xué)習(xí),并且通過與的實(shí)現(xiàn)方式進(jìn)行了對(duì)比,從而看出其變化以及快捷與便利。 ECMAScript 6.0(以下簡(jiǎn)稱 ES6)是 JavaScript 語(yǔ)言的下一代標(biāo)準(zhǔn),已經(jīng)在 2015 年 6 月正式發(fā)布了。它的目標(biāo),是使得 JavaScript 語(yǔ)言可...
摘要:塊級(jí)作用域存在于函數(shù)內(nèi)部塊中字符和之間的區(qū)域和塊級(jí)聲明用于聲明在指定塊的作用域之外無(wú)法訪問的變量。和都是塊級(jí)聲明的一種。值得一提的是聲明不允許修改綁定,但允許修改值。這意味著當(dāng)用聲明對(duì)象時(shí)沒有問題報(bào)錯(cuò)臨時(shí)死區(qū)臨時(shí)死區(qū),簡(jiǎn)寫為。 塊級(jí)作用域的出現(xiàn) 通過 var 聲明的變量存在變量提升的特性: if (condition) { var value = 1; } console.lo...
摘要:但對(duì)于引用類型的數(shù)據(jù)主要是對(duì)象和數(shù)組,變量指向的內(nèi)存地址,保存的只是一個(gè)引用地址指針,只能保證這個(gè)引用地址指針是固定的,至于它指向的堆內(nèi)存中的存儲(chǔ)的值是不是可變的,就完全不能控制了。 基礎(chǔ)概念 變量是存儲(chǔ)信息的容器,這里需要區(qū)分一下:變量不是指存儲(chǔ)的信息本身,而是指這個(gè)用于存儲(chǔ)信息的容器,可以把變量想象成一個(gè)個(gè)用來(lái)裝東西的紙箱子 變量需要聲明,并且建議在聲明的同時(shí)進(jìn)行初始化,如下所...
摘要:聲明的變量不得改變值,這意味著,一旦聲明變量,就必須立即初始化,不能留到以后賦值。這在語(yǔ)法上,稱為暫時(shí)性死區(qū),簡(jiǎn)稱。這表明函數(shù)內(nèi)部的變量與循環(huán)變量不在同一個(gè)作用域,有各自單獨(dú)的作用域。系列文章系列文章地址 showImg(https://segmentfault.com/img/bVbrjjC); 為什么需要塊級(jí)作用域 ES5 只有全局作用域和函數(shù)作用域,沒有塊級(jí)作用域,這帶來(lái)很多不合...
閱讀 5404·2023-04-25 19:30
閱讀 2264·2023-04-25 15:09
閱讀 2699·2021-11-16 11:45
閱讀 2279·2021-11-15 18:07
閱讀 1529·2021-11-11 17:22
閱讀 2192·2021-11-04 16:06
閱讀 3646·2021-10-20 13:47
閱讀 3092·2021-09-22 16:03