欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

面試官常問之說說js中var、let、const的區(qū)別

 更新時間:2022年03月09日 10:26:52   作者:款冬_  
var、let和const都是JavaScript中用來聲明變量的關(guān)鍵字,并且let和 const關(guān)鍵字是在 ES6 中才新增的,下面這篇文章主要給大家介紹了關(guān)于var、let、const區(qū)別的相關(guān)資料,需要的朋友可以參考下

前言

關(guān)于 var、let 和 const 三個關(guān)鍵字的區(qū)別,是一個老生常談的問題,也是經(jīng)典的面試題。本篇文章將全面講解三者的特性,以及它們之間的區(qū)別,由淺入深讓你徹底搞懂這個知識點。

變量聲明

ECMAScript 變量是松散類型的,意思就是變量可以用于保存任何類型的數(shù)據(jù),每個變量只不過是一個用于保存任意值的命名占位符。

有3個關(guān)鍵字可以聲明變量:var、let和const,var在 ECMAScript 的所有版本中都可以使用,而let和const只能在 ES6 及更晚的版本中使用。

var

要定義變量,可以使用var操作符(注意 var 是一個關(guān)鍵字),后跟變量名(即標識符,如前所述):

var message;

上面這行代碼定義了一個名為message的變量,它可以保存任何類型的值。不初始化的情況下,變量會保存一個特殊值undefined。

ECMAScript 實現(xiàn)變量初始化,因此可以同時定義變量并設(shè)置它的值:

var messgae = "hi";

message被定義為一個保存字符串值 "hi" 的變量。像這樣初始化變量不會將它標識為字符串類型,只是一個簡單的賦值而已。隨后,不僅可以改變保存的值,還可以改變值的類型:

var message = "hi";
message = 666; // 合法,但不推薦
console.log(message); // 666

如果需要定義多個變量,可以在一條語句中用逗號分隔每個變量(及可選的初始化):

var message,
    name = "孫悟空",
    age = 18;

作用域

使用var操作符定義的變量會成為包含它的函數(shù)的局部變量。例如,使用var在一個函數(shù)內(nèi)部定義一個變量,就意味著該變量將在函數(shù)退出時被銷毀:

function test() {
    var message = "hi"; // 局部變量
}
test();
console.log(message); // error: message is not defined

不過,在函數(shù)內(nèi)部定義變量時省略var操作符,可以創(chuàng)建一個全局變量:

function test() {
    message = "hi"; // 全局變量
}
test();
console.log(message); // ok

雖然可以通過省略var操作符定義全局變量,但不推薦這么做。在嚴格模式下,如果像這樣給未聲明的變量賦值,會報錯。

在同一個作用域內(nèi),反復(fù)多次使用var聲明同一個變量也是沒問題的:

function test() {
    var message = "hi";
    var message = false;
    var message = 666;

    console.log(message); 
}
test(); // 666

提升

所謂的提升,就是把所有變量聲明都拉到函數(shù)作用域的頂部。注意,只提升聲明,不提升賦值操作。

舉個栗子:

function test() {
    console.log(message);
    var message = "hi";
}
test(); // undefined

上面的代碼不會報錯,因為使用var關(guān)鍵字聲明的變量會提升到函數(shù)作用域的頂部,跟下面的代碼是等價的:

function test() {
    var message;
    console.log(message);
    message = "hi";
}
test(); // undefined

let

let 和 var 的作用差不多,但有著非常重要的區(qū)別。

作用域

var聲明的范圍是函數(shù)作用域,而let聲明的范圍是塊作用域:

if (true) {
    var message = "hi";
    console.log(message); // hi
}
console.log(message); // hi


if (true) {
    let message = "hi";
    console.log(message); // hi
}
console.log(message); // error: message is not defined

message變量之所以不能在 if 塊外部被引用,是因為它的作用域僅限于該塊內(nèi)部。塊作用域是函數(shù)作用域的子集,因此適用于var的作用域限制同樣也適用于let。

let 不允許同一個塊作用域中出現(xiàn)冗余聲明:

if (true) { 
    // error: 無法重新聲明塊范圍變量“a”
    let a;
    let a;
}

JS 引擎會記錄用于變量聲明的標識符及其所在的塊作用域,因此嵌套使用相同的標識符不會報錯,這是因為同一個塊中沒有重復(fù)聲明:

let a = 666;
console.log(a); // 666
if (true) {
    let a = '啊哈哈';
    console.log(a); // 啊哈哈
}

var和let聲明的并不是不同類型的變量,它們只是指出變量在相關(guān)作用域如何存在,所以對聲明冗余報錯不會因混用var和let而受影響:

// error
var a;
let a;

// error
let b;
var b;

暫時性死區(qū)

let聲明的變量不會在作用域中被提升:

if (true) {
    console.log(x); // error: 在賦值前使用了變量“x”
    let x = 520;
}

在解析代碼時,JS 引擎也會注意出現(xiàn)在塊后面的let聲明,只不過在此之前不能以任何方式來引用未聲明的變量。在let聲明之前的執(zhí)行瞬間被稱為暫時性死區(qū),在此階段引用任何后面才聲明的變量都會報錯。

const

const的行為與let基本相同,唯一一個重要的區(qū)別是:用const聲明變量時必須同時初始化變量,且嘗試修改const聲明的變量會導(dǎo)致運行時報錯:

const a; // error: 必須初始化 "const" 聲明

const b = 250;
b = 520; // error: 無法賦值給 "b" ,因為它是常數(shù)

注意,const聲明的限制只適用于它指向的變量的引用,換句話說,如果const變量引用的是一個對象,那么修改這個對象內(nèi)部的屬性并不違反const限制:

const obj = { x: 666 };
obj.x = 888; // ok
obj.y = '啊哈哈'; // ok

擴展

全局聲明

使用var在全局作用域中聲明的變量會成為window對象的屬性,let和const聲明的變量則不會:

var a = 666;
console.log(window.a); // 666

let b = 666;
console.log(window.b); // undefined

const c = 666;
console.log(window.c); // undefined

for 循環(huán)中的 let 聲明

先看個??:

for (var i = 0; i < 5; i++) {
    ...
}
console.log(i);

思考一下,打印結(jié)果會是什么?

由于var聲明的變量沒有塊作用域,所以迭代變量i會滲透到循環(huán)體外部,當i遞增到5時退出循環(huán),打印出結(jié)果為5。

如果用let聲明迭代變量,就可以把迭代變量的作用域限制為 for 循環(huán)塊內(nèi)部:

for (let i = 0; i < 5; i++) {
    ...
}
console.log(i); // error: i is not defined

再看個栗子:

for (var i = 0; i < 5; i++) {
    setTimeout( () => {
        console.log(i);
    }, 0 )
}

你可能以為會輸出:0、1、2、3、4,實際上會輸出:5、5、5、5、5。

之所以是這樣的結(jié)果,是因為在退出循環(huán)時,迭代變量保存的是導(dǎo)致循環(huán)退出的值,也就是 5。在之后異步執(zhí)行超時邏輯時,所有的i都是同一個變量,因此輸出的都是同一個最終值。

而在使用let聲明迭代變量時,JS 引擎在后臺會為每個迭代循環(huán)聲明一個新的迭代變量,每個 setTimeout 引用的都是不同的變量實例,所以 console.log 輸出的是我們期望的值,也就是循環(huán)執(zhí)行過程中每個迭代變量的值:

for (let i = 0; i < 5; i++) {
    setTimeout( () => {
        console.log(i); // 0、1、2、3、4
    }, 0 )
}

這是一道經(jīng)典面試題,不是很理解的話一定要多看幾遍,最好動手實踐一下,徹底搞懂為止。

總結(jié)

  • var 聲明的范圍是函數(shù)作用域,let 和 const 聲明的范圍是塊作用域

  • var 聲明的變量會被提升到函數(shù)作用域的頂部,let 和 const 聲明的變量不存在提升,且具有暫時性死區(qū)特征

  • var 允許在同一個作用域中重復(fù)聲明同一個變量,let 和 const 不允許

  • 在全局作用域中使用 var 聲明的變量會成為 window 對象的屬性,let 和 const 聲明的變量則不會

  • const 的行為與 let 基本相同,唯一一個重要的區(qū)別是,使用 const 聲明的變量必須進行初始化,且不能被修改

聲明風(fēng)格及最佳實踐

ECMAScript 6 增加 let 和 const 從客觀上為這門語言更精確地聲明作用域和語義提供了更好的支持,行為怪異的 var 所造成的問題,已經(jīng)讓 JS 社區(qū)為之苦惱了很多年。隨著這兩個關(guān)鍵字的出現(xiàn),新的有助于提升代碼質(zhì)量的最佳實踐方式也逐漸顯現(xiàn)。

var 已經(jīng)被時代所拋棄,不建議再使用。限制自己只使用 let 和 const 有助于提升代碼質(zhì)量,因為變量有了明確的作用域、聲明位置以及不變的值。

優(yōu)先使用 const,let 次之。使用 const 聲明可以讓瀏覽器運行時強制保持變量不變,也可以讓靜態(tài)代碼分析工具提前發(fā)現(xiàn)不合法的賦值操作。只在提前知道未來會有修改時,才使用 let。這樣可以讓開發(fā)者更有信心地推斷某些變量的值永遠不會變,同時也能迅速發(fā)現(xiàn)因意外賦值導(dǎo)致的非預(yù)期行為。

到此這篇關(guān)于ja中var、let、const區(qū)別的文章就介紹到這了,更多相關(guān)var、let、const區(qū)別內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評論