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