js 中 var let const 解析

一.var
含義:變量聲明,無論發(fā)生在何處顽素,都在執(zhí)行任何代碼之前進(jìn)行處理讯屈。

注意:
1.聲明變量的作用域限制在其聲明位置的上下文中,而非聲明變量總是全局的

function x() {  
  y = 1;  // 在嚴(yán)格模式(strict mode)下會(huì)拋出ReferenceError異常嚎于。  
  var z = 2;
}
x();
console.log(y); // 打印"1" 。
console.log(z); // 拋出ReferenceError: z未在x外部聲明昼伴。

2. 聲明變量在任何代碼執(zhí)行前創(chuàng)建匾旭,而非聲明變量只有在執(zhí)行賦值操作的時(shí)候才會(huì)被創(chuàng)建。

console.log(a);   // 拋出ReferenceError圃郊。console.log('still going...'); // 永不執(zhí)行。

var a;
console.log(a);  // 打印"undefined"或""(不同瀏覽器實(shí)現(xiàn)不同)女蜈。
console.log('still going...'); // 打印"still going..."

3. 聲明變量是它所在上下文環(huán)境的不可配置屬性持舆,非聲明變量是可配置的(如非聲明變量可以被刪除)。

var a = 1;b = 2;
delete this.a; // 在嚴(yán)格模式(strict mode)下拋出TypeError伪窖,其他情況下執(zhí)行失敗并無任何提示逸寓。
delete this.b;
console.log(a, b); // 拋出ReferenceError。// 'b'屬性已經(jīng)被刪除覆山。

建議:建議始終聲明變量竹伸,無論它們是在函數(shù)還是全局作用域內(nèi)。

參考例子:
變量提升:

 var a = 2;
 function foo() {
     console.log(a); //undefined
     var a = 10;
     console.log(a); //10
 }
 foo();

留意其中的順序:

var x = y, y = 'A';
console.log(x + y); // undefinedA

在這里簇宽,x和y在代碼執(zhí)行前就已經(jīng)創(chuàng)建了勋篓,而賦值操作發(fā)生在創(chuàng)建之后。當(dāng)"x = y"執(zhí)行時(shí)魏割,y已經(jīng)存在譬嚣,所以不拋出ReferenceError,并且它的值是'undefined'钞它。所以x被賦予 undefined 值拜银。然后殊鞭,y被賦予'A'。于是在執(zhí)行完第一行之后尼桶,x === undefined && y === 'A'才出現(xiàn)了這樣的結(jié)果操灿。

多個(gè)變量的初始化

var x = 0;
function f(){  
  var x = y = 1; // x在函數(shù)內(nèi)部聲明,y不是泵督!
}
f();
console.log(x, y); // 0, 1// x是全局變量趾盐。// y是隱式聲明的全局變量。

隱式全局變量和外部函數(shù)作用域

看起來像是隱式全局作用域的變量也有可能是其外部函數(shù)變量的引用幌蚊。

var x = 0;  // x是全局變量谤碳,并且賦值為0。
console.log(typeof z); // undefined溢豆,因?yàn)閦還不存在蜒简。
function a() { // 當(dāng)a被調(diào)用時(shí),  
  var y = 2;  // y被聲明成函數(shù)a作用域的變量漩仙,然后賦值成2搓茬。        
  console.log(x, y);  // 0 2  
  function b() {      // 當(dāng)b被調(diào)用時(shí),    
    x = 3;  // 全局變量x被賦值為3队他,不生成全局變量卷仑。   
    y = 4;  // 已存在的外部函數(shù)的y變量被賦值為4,不生成新的全局變量麸折。      z = 5;  // 創(chuàng)建新的全局變量z锡凝,并且給z賦值為5。  
  }        // (在嚴(yán)格模式下(strict mode)拋出ReferenceError)  b();    // 調(diào)用b時(shí)創(chuàng)建了全局變量z垢啼。  
  console.log(x, y, z);  // 3 4 5
}
a();                  // 調(diào)用a時(shí)同時(shí)調(diào)用了b窜锯。
console.log(x, z);    // 3 5
console.log(typeof y); // undefined,因?yàn)閥是a函數(shù)的本地(local)變量芭析。

二.let

含義:允許你聲明一個(gè)作用域被限制在塊級(jí)中的變量锚扎、語句或者表達(dá)式。與var關(guān)鍵字不同的是馁启,它聲明的變量只能是全局或者整個(gè)函數(shù)塊的驾孔。

注意:let聲明的變量只在其聲明的塊或子塊中可用,這一點(diǎn)惯疙,與var相似翠勉。二者之間最主要的區(qū)別在于var聲明的變量的作用域是整個(gè)封閉函數(shù)。

function varTest() {  
  var x = 1;  
  if (true) {    
    var x = 2;  // 同樣的變量!   
    console.log(x);  // 2 
   }  
  console.log(x);  // 2
}
function letTest() {  
  let x = 1;  
  if (true) {   
    let x = 2;  // 不同的變量    
    console.log(x);  // 2  
 } 
 console.log(x);  // 1
}

作用:

1.簡(jiǎn)化內(nèi)部函數(shù)代碼

當(dāng)用到內(nèi)部函數(shù)的時(shí)候螟碎,let會(huì)讓你的代碼更加簡(jiǎn)潔眉菱。

var list = document.getElementById('list');
for (let i = 1; i <= 5; i++) {  
  let item = document.createElement('li');         
  item.appendChild(document.createTextNode('Item ' + i)); 
  item.onclick = function(ev) { 
    console.log('Item ' + i + ' is clicked.');  };
  list.appendChild(item);
}// to achieve the same effect with 'var'// you have to create a different context// using a closure to preserve the value
for (var i = 1; i <= 5; i++) {  
  var item = document.createElement('li'); 
  item.appendChild(document.createTextNode('Item ' + i)); 
  (function(i){    
  item.onclick = function(ev) {  
    console.log('Item ' + i + ' is clicked.');   
  };  
})(i);  
list.appendChild(item);
}

以上示例的工作原理是因?yàn)椋涿﹥?nèi)部函數(shù)的五個(gè)實(shí)例引用了變量i的五個(gè)不同實(shí)例。注意掉分,如果你將let替換為var俭缓,則它將無法正常工作克伊,因?yàn)樗袃?nèi)部函數(shù)都將返回相同的i:6的最終值。此外华坦,我們可以通過將創(chuàng)建新元素的代碼移動(dòng)到每個(gè)循環(huán)的作用域來保持循環(huán)更清晰愿吹。

每次循環(huán)的i其實(shí)都是一個(gè)新的變量 注意for循環(huán)的作用域(父子作用域)

在程序或者函數(shù)的頂層,let并不會(huì)像var一樣在全局對(duì)象上創(chuàng)造一個(gè)屬性惜姐,比如:

var x = 'global';
let y = 'global';
console.log(this.x); // "global"
console.log(this.y); // undefined

2.模仿私有接口

在處理構(gòu)造函數(shù)的時(shí)候犁跪,可以通過let綁定來共享一個(gè)或多個(gè)私有成員,而不使用閉包:

var Thing;
{  
   let privateScope = new WeakMap();  
   let counter = 0; 
   Thing = function() {    
   this.someProperty = 'foo';   
    privateScope.set(this, {
    hidden: ++counter,    
   });  
  };  
  Thing.prototype.showPublic = function() {    
    return this.someProperty;  
  };  
  Thing.prototype.showPrivate = function() {    
    return privateScope.get(this).hidden;  
  };
}
console.log(typeof privateScope);// "undefined"
var thing = new Thing();
console.log(thing);// Thing {someProperty: "foo"}
thing.showPublic();// "foo"
thing.showPrivate();// 1

暫存死區(qū)的錯(cuò)誤

在相同的函數(shù)或塊作用域內(nèi)重新聲明同一個(gè)變量會(huì)引發(fā)SyntaxError歹袁。

if (x) {  
  let foo;
  let foo; // TypeError thrown.
}

在 ECMAScript 2015 中坷衍,let綁定不受變量提升的約束,這意味著let聲明不會(huì)被提升到當(dāng)前執(zhí)行上下文的頂部条舔。在塊中的變量初始化之前枫耳,引用它將會(huì)導(dǎo)致ReferenceError(而使用 var 聲明變量則恰恰相反,該變量的值是 undefined )孟抗。該變量處于從塊開始到初始化處理的“暫存死區(qū)”迁杨。

function do_something() {
  console.log(bar); // undefined
  console.log(foo); // ReferenceError: foo is not defined
  var bar = 1;
  let foo = 2;
}

在switch聲明中你可能會(huì)遇到這樣的錯(cuò)誤,因?yàn)樗挥幸粋€(gè)塊.

switch (x) {
  case 0:
    let foo;
    break;   
  case 1:
    let foo; // TypeError for redeclaration.
    break;
}

但是凄硼,重要的是要指出嵌套在case子句內(nèi)的塊將創(chuàng)建一個(gè)新的塊作用域的詞法環(huán)境铅协,這不會(huì)產(chǎn)生上面顯示的重新聲明錯(cuò)誤。

let x = 1;
switch(x) {
  case 0: {
    let foo;
    break;
  } 
  case 1: {
    let foo;
    break;  }
}

與詞法作用域結(jié)合的暫存死區(qū)

由于詞法作用域摊沉,表達(dá)式(foo + 55)內(nèi)的標(biāo)識(shí)符“foo”會(huì)解析為if塊的foo狐史,而不是覆蓋值為33的foo。在這一行中说墨,if塊的“foo”已經(jīng)在詞法環(huán)境中創(chuàng)建预皇,但尚未達(dá)到(并終止)其初始化(這是語句本身的一部分):它仍處于暫存死區(qū)。

function test(){
  var foo = 33;
  if (true) {
      let foo = (foo + 55); // ReferenceError
  }
}
test();

這種現(xiàn)象可能會(huì)使您陷入以下情況婉刀。指令let n of n.a已經(jīng)在for循環(huán)塊的私有范圍內(nèi),因此標(biāo)識(shí)符“n.a”被解析為位于指令本身的第一部分(“l(fā)et n”)中的'n'對(duì)象的屬性'a' 序仙,由于尚未達(dá)成和終止其聲明突颊,因此仍處于暫存死區(qū)。

function go(n) {
  // n here is defined!
  console.log(n); // Object {a: [1,2,3]}
  for (let n of n.a) { // ReferenceError    console.log(n);
  }
}
go({a: [1, 2, 3]});

一.const

含義:此聲明創(chuàng)建一個(gè)常量潘悼,其作用域可以是全局或本地聲明的塊律秃。 與var變量不同,全局常量不會(huì)變?yōu)榇翱趯?duì)象的屬性治唤。需要一個(gè)常數(shù)的初始化器棒动。

注意:

// 注意: 常量在聲明的時(shí)候可以使用大小寫,但通常情況下全部用大寫字母宾添。

// 定義常量MY_FAV并賦值7
const MY_FAV = 7;
// 報(bào)錯(cuò)
MY_FAV = 20;
// 輸出 7
console.log("my favorite number is: " + MY_FAV);
// 嘗試重新聲明會(huì)報(bào)錯(cuò) 
const MY_FAV = 20;
//  MY_FAV 保留給上面的常量船惨,這個(gè)操作會(huì)失敗
var MY_FAV = 20; 
// 也會(huì)報(bào)錯(cuò)
let MY_FAV = 20;
// 注意塊范圍的性質(zhì)很重要
if (MY_FAV === 7) {
// 沒問題柜裸,并且創(chuàng)建了一個(gè)塊作用域變量 
MY_FAV    
// (works equally well with let to declare a block scoped non const variable)    
let MY_FAV = 20;    
// MY_FAV 現(xiàn)在為 20    
console.log('my favorite number is ' + MY_FAV);    
// 這被提升到全局上下文并引發(fā)錯(cuò)誤    
var MY_FAV = 20;}
// MY_FAV 依舊為7
console.log("my favorite number is " + MY_FAV);
// 常量要求一個(gè)初始值
const FOO; 
// SyntaxError: missing = in const declaration
// 常量可以定義成對(duì)象
const MY_OBJECT = {"key": "value"};
// 重寫對(duì)象和上面一樣會(huì)失敗
MY_OBJECT = {"OTHER_KEY": "value"};
// 對(duì)象屬性并不在保護(hù)的范圍內(nèi),下面這個(gè)聲明會(huì)成功執(zhí)行
MY_OBJECT.key = "otherValue";// 也可以用來定義數(shù)組
const MY_ARRAY = [];
// It's possible to push items into the array
// 可以向數(shù)組填充數(shù)據(jù)
MY_ARRAY.push('A'); 
// ["A"]
// 但是粱锐,將一個(gè)新數(shù)組賦給變量會(huì)引發(fā)錯(cuò)誤MY_ARRAY = ['B']
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末疙挺,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子怜浅,更是在濱河造成了極大的恐慌铐然,老刑警劉巖,帶你破解...
    沈念sama閱讀 210,914評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件恶座,死亡現(xiàn)場(chǎng)離奇詭異搀暑,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)跨琳,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,935評(píng)論 2 383
  • 文/潘曉璐 我一進(jìn)店門自点,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人湾宙,你說我怎么就攤上這事樟氢。” “怎么了侠鳄?”我有些...
    開封第一講書人閱讀 156,531評(píng)論 0 345
  • 文/不壞的土叔 我叫張陵埠啃,是天一觀的道長。 經(jīng)常有香客問我伟恶,道長碴开,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,309評(píng)論 1 282
  • 正文 為了忘掉前任博秫,我火速辦了婚禮潦牛,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘挡育。我一直安慰自己巴碗,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,381評(píng)論 5 384
  • 文/花漫 我一把揭開白布即寒。 她就那樣靜靜地躺著橡淆,像睡著了一般。 火紅的嫁衣襯著肌膚如雪母赵。 梳的紋絲不亂的頭發(fā)上逸爵,一...
    開封第一講書人閱讀 49,730評(píng)論 1 289
  • 那天,我揣著相機(jī)與錄音凹嘲,去河邊找鬼师倔。 笑死,一個(gè)胖子當(dāng)著我的面吹牛周蹭,可吹牛的內(nèi)容都是我干的趋艘。 我是一名探鬼主播疲恢,決...
    沈念sama閱讀 38,882評(píng)論 3 404
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼致稀!你這毒婦竟也來了冈闭?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,643評(píng)論 0 266
  • 序言:老撾萬榮一對(duì)情侶失蹤抖单,失蹤者是張志新(化名)和其女友劉穎萎攒,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體矛绘,經(jīng)...
    沈念sama閱讀 44,095評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡耍休,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,448評(píng)論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了货矮。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片羊精。...
    茶點(diǎn)故事閱讀 38,566評(píng)論 1 339
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖囚玫,靈堂內(nèi)的尸體忽然破棺而出喧锦,到底是詐尸還是另有隱情,我是刑警寧澤抓督,帶...
    沈念sama閱讀 34,253評(píng)論 4 328
  • 正文 年R本政府宣布燃少,位于F島的核電站,受9級(jí)特大地震影響铃在,放射性物質(zhì)發(fā)生泄漏阵具。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,829評(píng)論 3 312
  • 文/蒙蒙 一定铜、第九天 我趴在偏房一處隱蔽的房頂上張望阳液。 院中可真熱鬧,春花似錦揣炕、人聲如沸帘皿。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,715評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽矮烹。三九已至,卻和暖如春罩锐,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背卤唉。 一陣腳步聲響...
    開封第一講書人閱讀 31,945評(píng)論 1 264
  • 我被黑心中介騙來泰國打工涩惑, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人桑驱。 一個(gè)月前我還...
    沈念sama閱讀 46,248評(píng)論 2 360
  • 正文 我出身青樓竭恬,卻偏偏與公主長得像跛蛋,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子痊硕,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,440評(píng)論 2 348

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