摘要:塊級作用域存在于兩個地方函數內部。如下例應該返回創建數組的構造函數即這是數組返回這是數組從上例,我們可以知道即使全局作用域中已經定義了變量或者已經存在了屬性,但我們之后定義的變量則會覆蓋之前已經定義好的或者已經存在的變量屬性。
一.var 聲明與變量提升機制
在JavaScript中使用var定義一個變量,無論是定義在全局作用域函數函數的局部作用域中,都會被提升到其作用域的頂部,這也是JavaScript定義變量的一個令人困惑的地方。由于es5沒有像其它類C語言一樣的塊級作用域,因此es6增加了let定義變量,用來創建塊級作用域。
我們來看一個var定義變量的示例:
function setName(){ if(condition){ var name = "loho"; console.log(name); }else{ console.log(name); } } var student = "eveningwater"; setName();
以上代碼可以理解成如下:
var student; function setName(){ var name; if(condition){ name = "loho"; console.log(name);//loho }else{ console.log(name);//undefined } } student = "eveningwater"; setName();二.塊級聲明
塊級聲明意在指定一個塊級作用域,使得塊級作用域中所定義的變量無法再全局被訪問到,塊級作用域也被稱為詞法作用域。
塊級作用域存在于兩個地方:
函數內部。
指定代碼塊中。(即"{"和"}"之間的區域)
1.let 聲明let聲明同var聲明用法一致,唯一的區別在于,let聲明將變量限制在一個塊內,這樣就形成了一個塊級作用域,因此也就不會存在變量的提升了。
例如前面的示例,我們可以寫成如下:
let stundent = "eveningwater"; function setName(){ if(condition){ let name = "loho"; console.log(name);//loho }else{ //如果條件為false執行到這里 console.log(name);//不返回值 } } setName();2.禁止重聲明
在使用let定義變量之前如果已經聲明了相同的變量,就會報錯。因此不能重復聲明變量。如以下示例:
var name = "eveningwater"; //報錯,重復聲明 let name = "loho";
當然這兩個變量必須是在同一個作用域中,如果是不同作用域中,則不會報錯。但有可能會遮蔽第一次聲明的變量。如以下示例:
var name = "eveningwater"; if(condition){ //不會報錯 let name = "loho"; }3.const聲明
使用const標識符所聲明的變量必須要初始化,因此這個聲明的就是一個常量。如下例:
const name="eveningwater";//正確 const name;//錯誤,未初始化
const聲明同let聲明一樣,也是創建了一個塊級作用域,在這個塊級作用域之外是無法訪問到所聲明的變量的。換句話說,就是const所聲明的變量不會有變量提升機制。如下例:
if(condition){ const name = "eveningwater"; console.log(name);//"eveningwater" } //錯誤 console.log(name);
同樣的const也不能重復聲明,如下例:
var name = "eveningwater"; //錯誤,不能重復聲明 const name = "loho";
但也可以在不同作用域中重復聲明,如下例:
var name = "eveningwater"; if(condition){ const name = "loho"; console.log(name);//loho,屏蔽全局定義的變量 }
盡管const聲明與let聲明有太多相似的地方,但const聲明也有一處與let聲明不同,那就是const聲明的變量不能被賦值,無論是在非嚴格模式下還是在嚴格模式下,都不能對const聲明的變量進行賦值。如下例:
const name = "eveningwater"; //錯誤 name = "loho";
不過,如果定義的是一個對象,可以對對象的值進行修改,如下例:
const student = { name:"eveningwater" } student.name = "loho";//沒問題 //錯誤,相當于賦值修改對象 student = { name:"loho" }4.臨時死區
前面提到let和const聲明的變量都不會提升到作用域的頂部,因此在使用這兩個標識符聲明之前訪問會報錯,即使是typeof操作符也會觸發引用錯誤。如下例:
console.log(typeof name);//報錯 const name = "eveningwater";
由于第一行代碼就報錯了,因此后續的聲明變量語句不會執行,此時就出現了JavaScript社區所謂的"臨時死區"(temporal dead zone).雖然這里示例是const聲明,但let聲明也是一樣的。
但如果在const或let聲明的變量的作用域之外使用typeof操作符監測卻不會報錯,只不過會返回undefined。如下例:
console.log(typeof name);//undefined if(condition){ let name = "eveningwater"; }5.循環中的塊級作用域綁定
我們在使用var聲明變量的時候,總會遇到這樣的情況,如下:
for(var i = 0;i < 100;i++){ //執行某些操作 } //這里也能訪問到變量i console.log(i);//100
我們可以使用let聲明將變量i限制在循環中,此時再在循環作用域之外訪問變量i就會報錯了,因為let聲明已經為循環創建了一個塊級作用域。如下:
for(let i = 0;i < 100;i++){ //執行某些操作 } //報錯 console.log(i);6.循環中的創建函數
在使用var聲明變量的循環中,創建一個函數非常的困難,如下例:
var func = []; for(var i = 0;i < 5;i++){ func.push(function(){ console.log(i); }) } func.forEach(function(func){ func(); });
你可能預期想的是打印從0到5之間,即0,1,2,3,4的數字,但實際上答案并不是如此。由于函數有自己的作用域,因此在向數組中添加函數的時候,實際上循環已經運行完成,因此每次打印變量i的值都相當于是在全局中訪問變量i的值,即i = 5這個值,因此實際上答案最終會返回5次5.
在es5中,我們可以使用函數表達式(IIFE)來解決這個問題,因為函數表達式會創建一個自己的塊級作用域。如下:
var func = []; for(var i = 0;i < 5;i++){ (function(i){ func.push(function(){ console.log(i); }) })(i) } func.forEach(function(func){ func();//這就是你想要的答案,輸出0,1,2,3,4 })
;
但事實上有了es6的let聲明,我們不必如此麻煩,只需要將var變成let聲明就可以了,如下:
var func = []; for(let i = 0;i < 5;i++){ func.push(function(){ console.log(i); }) } func.forEach(function(func){ func();//輸出0,1,2,3,4 })
但是這里不能使用const聲明,因為前面提到過,const聲明并初始化了一個常量之后是不能被修改的,只能在對象中被修改值。如以下示例就會報錯:
//在執行循環i++條件的時候就會報錯 for(const i = 0;i < len;i++){ console.log(i); }
因為i++這個語句就是在嘗試修改常量i的值,因此不能將const聲明用在for循環中,但可以將const聲明用在for-in或者for-of循環中。如下:
var func = []; var obj = { name:"eveningwater", age:22 } for(let key in obj){ func.push(function(){ console.log(key) }) } func.forEach(function(func){ func();//name,age }); //以下也沒問題 var func = []; var obj = { name:"eveningwater", age:22 } for(const key in obj){ func.push(function(){ console.log(key) }) } func.forEach(function(func){ func();//name,age });
這里并沒有修改key的值,因此使用const和let聲明都可以,同理for-of循環也是一樣的道理。for-of循環是es6的新增的循壞。。
7.全局作用域綁定let,const聲明與var聲明還有一個區別就是三者在全局作用域中的行為。當使用var聲明一個變量時,會在全局作用域(通常情況下是瀏覽器window對象)中創建一個全局屬性,這也就意味著可能會覆蓋window對象中已經存在的一個全局變量。如下例:
console.log(window.Array);//應該返回創建數組的構造函數,即f Array(){} var Array = "這是數組"; console.log(window.Array);//返回"這是數組";
從上例,我們可以知道即使全局作用域中已經定義了Array變量或者已經存在了Array屬性,但我們之后定義的Array變量則會覆蓋之前已經定義好的或者已經存在的Array變量(屬性)。
但是es6的let和const聲明則不會出現這種情況,let和const聲明會創建一個新的綁定,也就是說不會成為window對象的屬性。換句話說,就是所聲明的變量不會覆蓋全局變量,而只會遮蔽它。如下例:
let Array = "這是數組"; console.log(Array);//"這是數組‘; console.log(window.Array);//應該返回創建數組的構造函數,即f Array(){}
這也就是說window.Array !== Array這個等式返回布爾值true。
8.塊級綁定的最佳實踐在使用es6塊級聲明變量中,最佳實踐是如果確定后續不會改變這個變量的值,用const聲明,如果確定要改變這個變量的值,則用let聲明。因為預料外的變量值的改變時很多bug出現的源頭。如下示例:
function eveningWater(){}; eveningWater.prototype.name = "eveningwater"; let ew = new eveningWater(); //定義不能被修改的變量,也就是用于判斷實例類型的屬性 const _constructor = ew.constructor; //可以改變自定義的名字屬性 let name = ew.name; if(_constructor === eveningWater || _constuctor === Object){ console.log(_constructor); }else{ name = "loho"; console.log(name) }
鄙人創建了一個QQ群,供大家學習交流,希望和大家合作愉快,互相幫助,交流學習,以下為群二維碼:
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/102907.html
摘要:外層作用域不報錯正常輸出塊級作用域與函數聲明規定,函數只能在頂層作用域和函數作用域之中聲明,不能在塊級作用域聲明。規定,塊級作用域之中,函數聲明語句的行為類似于,在塊級作用域之外不可引用。同時,函數聲明還會提升到所在的塊級作用域的頭部。 前言:最近開始看阮一峰老師的《ECMAScript 6 入門》(以下簡稱原...
摘要:和塊級作用域在高程中,作者強調說沒有塊級作用域。然而,這種情況在中發生了改變,通過在代碼塊中使用引入了塊級作用域的特性。在塊級作用域內部使用聲明的變量,在塊作用域外部是不可見的。 let const和塊級作用域 在js高程中,作者強調說js沒有塊級作用域。然而,這種情況在es6中發生了改變,es6通過在代碼塊中使用let, const引入了塊級作用域的特性。下面是對此特性的介紹。 語法...
摘要:入門一前言由于最近本人在學習,做一些筆記能夠更好的熟悉,就趁此機會來寫一篇關于的新人學習摘要吧。的作用域與命令相同只在聲明所在的塊級作用域內有效。塊級作用域新增方式和實際上為新增了塊級作用域。同時,函數聲明還會提升到所在的塊級作用域的頭部。 ECMAScript6/ES6 入門 一、前言 由于最近本人在學習ES6,做一些筆記能夠更好的熟悉,就趁此機會來寫一篇關于ES6的新人學習摘要吧。...
摘要:和命令命令是在它所在的代碼塊有效,它屬于塊級作用域,新增。只有全局作用域和函數作用域。 let和const命令 let命令是在它所在的代碼塊有效,它屬于塊級作用域,es6新增。es5只有全局作用域和函數作用域。let命令存在暫時性死區(TDZ),即在申明前使用就會報錯,不存在變量提升 console.log(a); // 報錯 let a = 111; ==let不允許在相同作用域中,...
摘要:允許在塊級作用域內聲明函數。上面代碼中,存在全局變量,但是塊級作用域內又聲明了一個局部變量,導致后者綁定這個塊級作用域,所以在聲明變量前,對賦值會報錯。 ES5的作用域 變量起作用的范圍,js中能創建作用域的只能是函數 { let a = 1; var b = 2; } console.log(a); // a is not defined console.log(b); //...
摘要:命令新增了命令,跟類似,都是用來聲明變量的不允許重復聲明報錯不存在變量提升報錯正確寫法為既要先定義,后面才能有這個值,否則會報錯,如果改成會提示未定義,但是就直接報錯了暫時性死區只要在塊級作用域里面存在則它所聲明的變量就綁定在這個塊級作用域 let命令 ES6新增了let命令,跟var類似,都是用來聲明變量的 1.不允許重復聲明 { let a = 1; let a =...
閱讀 4365·2021-11-24 10:24
閱讀 1409·2021-11-22 15:22
閱讀 2038·2021-11-17 09:33
閱讀 2428·2021-09-22 15:29
閱讀 515·2019-08-30 15:55
閱讀 1652·2019-08-29 18:42
閱讀 2731·2019-08-29 12:55
閱讀 1772·2019-08-26 13:55