亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

javascript中的var、let、const最佳實(shí)踐

 更新時(shí)間:2025年07月01日 09:36:09   作者:前端風(fēng)云志  
var,let and const是JavaScript中三種定義變量的方式,它們之間有什么區(qū)別呢?下面給大家介紹javascript中的var、let、const最佳實(shí)踐,感興趣的朋友一起看看吧

簡(jiǎn)介

varlet and const是JavaScript中三種定義變量的方式,它們之間有什么區(qū)別呢?這是前端面試中常見的一道題,今天我們來(lái)一文說(shuō)透它。
letconst區(qū)別不大,主要是const聲明的是常量,不可修改,而let聲明的變量是可修改的。所以我們重點(diǎn)放在varlet上。

變量初始化

聲明變量的同時(shí)為其賦值叫做初始化。

  • varlet聲明的變量都可以不賦值,此時(shí)變量的值為undefined。
  • const聲明的變量必須賦值,否則會(huì)報(bào)錯(cuò)。
// `var`和`let`聲明的變量可以不賦值,此時(shí)變量的值為`undefined`。
var num; // num的值是undefined
num = 1; // num的值是1
let str; // str的值是undefined
str = 'hello'; // str的值是'hello' 
// `const`聲明的變量必須賦值,否則會(huì)報(bào)錯(cuò)。
const a; // SyntaxError: Missing initializer in const declaration

變量提升 - Hoisting

Hoisting這個(gè)詞中文譯為提升,就是將變量的聲明提升到其作用域的頂部,注意提升的是聲明,而不是賦值。

  • var聲明的變量會(huì)被提升至其作用域頂部。
  • letconst聲明的變量不會(huì)被提升。(注意這個(gè)說(shuō)法有爭(zhēng)議,詳見MDN
  • 提升只針對(duì)變量聲明,不包括賦值。

如果var是在全局作用域聲明的,那么它會(huì)被提升到全局作用域的頂部。

console.log(name); // undefined
var name = 'Philip';

以上代碼等價(jià)于:

var name; // `var`聲明的變量會(huì)被提升到其作用域頂部。
console.log(name); // undefined
name = 'Philip';

如果var是在函數(shù)作用域聲明的,那么它會(huì)被提升到函數(shù)作用域的頂部。

function printName() {
  console.log(name); // undefined
  var name = 'Philip';
}
printName();

以上代碼等價(jià)于:

function printName() {
  var name; // `var`聲明的變量會(huì)被提升到其作用域頂部。
  console.log(name); // undefined
  name = 'Philip';
}
printName();

let和const聲明的變量不會(huì)被提升。

對(duì)于letconst,它們不會(huì)被提升,所以下面代碼會(huì)報(bào)錯(cuò)。

console.log(num); // ReferenceError: Cannot access 'num' before initialization
const num = 1;

前面說(shuō)過,關(guān)于letconst是否被提升有爭(zhēng)議。

  • 一種說(shuō)法是letconst不會(huì)被提升,所以在聲明之前訪問會(huì)報(bào)錯(cuò)。
  • 另一種說(shuō)法是letconst會(huì)被提升,但是在聲明之前訪問會(huì)拋出Temporal Dead Zone錯(cuò)誤。

比如下面的代碼:

const x = 1;
{
  console.log(x); // ReferenceError: Cannot access 'x' before initialization
  const x = 2;
}

這段代碼會(huì)報(bào)錯(cuò),但是如果我們把{}內(nèi)的const x = 2;注釋掉,那么代碼就不會(huì)報(bào)錯(cuò)。如果const x = 2沒有被提升的話,那么console.log(x)應(yīng)該可以訪問到全局的const x = 1,而不會(huì)報(bào)錯(cuò)。換句話說(shuō):因?yàn)?code>const x = 2被提升了,所以console.log(x)訪問的是提升后的x,而此時(shí)x還沒有被初始化,所以報(bào)錯(cuò)。

提升只針對(duì)變量聲明,不包括賦值。

下面的代碼會(huì)報(bào)錯(cuò),因?yàn)閤 = 1是賦值,并不是聲明,所以不會(huì)提升。(注意:如果變量聲明前沒有加varletconst,那么其實(shí)產(chǎn)生的是一個(gè)意外的全局變量。)

console.log(x); // ReferenceError: x is not defined
x = 1;

如果有同名函數(shù)和變量,那么提升后,變量位于函數(shù)之前(或者說(shuō)函數(shù)會(huì)覆蓋變量)。

以下代碼中有一個(gè)同名的函數(shù)和變量。

console.log(foo); // [Function: foo], not undefined.
function foo() {
  console.log('function foo');
}
var foo = 1;

提升后代碼如下:

var foo;
function foo() {
  console.log('function foo');
}
console.log(foo);
foo = 1;

面試題

看幾道面試題,以下幾段代碼輸出什么?

  • 第一題
a = 2;
var a;
console.log(a); // 2

解決var提升的問題很簡(jiǎn)單,就是按照提升規(guī)則將代碼重寫一下,上面的代碼等價(jià)于如下代碼,結(jié)果一目了然。

var a;
a = 2;
console.log(a); // 2
  • 第二題
var a = true;
foo();
function foo() {
  if (a) {
    var a = 10;
  }
  console.log(a);
}

只要函數(shù)內(nèi)部有var聲明的變量,那么所有全局聲明的var變量都會(huì)被忽略,以上代碼提升后等價(jià)于如下代碼(注意function也有提升),函數(shù)內(nèi)部的var永遠(yuǎn)會(huì)覆蓋全局的var

var a = true;
function foo() {
  var a; // value of a is `undefined`
  if (a) {
    a = 10; // never executed.
  }
  console.log(a);
}
foo();
  • 第三題
function fn() {
  console.log(typeof foo);
  var foo = 'variable';
  function foo() {
    return 'function';
  }
  console.log(typeof foo);
}
fn();

還是那句話,此類題目的解法就是按照提升規(guī)則把代碼重新寫一遍,以上代碼提升后等價(jià)于如下代碼:

function fn() {
  var foo;
  function foo() {
    return 'function';
  }
  console.log(typeof foo);
  foo = 'variable';
  console.log(typeof foo);
}
fn();

所以輸出結(jié)果是functionstring。

變量的作用域

  • var聲明的變量有只兩種作用域:全局作用域和函數(shù)作用域。(沒有塊級(jí)作用域)
  • letconst聲明的變量有三種作用域:全局作用域,函數(shù)作用域和塊級(jí)作用域。
  • var聲明的全局變量會(huì)掛載到window對(duì)象上,而letconst不會(huì)。
  • letconst有臨時(shí)性死區(qū),而var沒有。

面試題

第一題

以下代碼輸出什么?

let x = 1;
{
  let x = 2;
}
console.log(x);

答案:1,因?yàn)?code>let有塊級(jí)作用域,所以let x = 2只在{}內(nèi)有效。

第二題

以下代碼輸出什么?

var x = 1;
{
  var x = 2;
}
console.log(x);

答案:2,因?yàn)?code>var沒有塊級(jí)作用域,所以var x = 2會(huì)覆蓋外部的var x = 1。

第三題

以下代碼輸出什么?

let name = 'zdd';
{
  console.log(name); 
  let name = 'Philip';
}

答案:ReferenceError: Cannot access 'name' before initialization。因?yàn)?code>let有塊級(jí)作用域,所以console.log(name);訪問的是let name = 'Philip';之前的name,而此時(shí)name還沒有被初始化,處于暫時(shí)性死區(qū)中,所以報(bào)錯(cuò)。

第四題

以下代碼輸出什么?

'use strict';
{
  function foo() {
    console.log('foo');
  }
}
foo();

答案:ReferenceError: foo is not defined。因?yàn)?code>foo是在塊級(jí)作用域內(nèi)聲明的,所以在外部無(wú)法訪問。但是如果我們把'use strict';去掉,那么代碼就可以正常運(yùn)行。因?yàn)樵诜菄?yán)格模式下,函數(shù)聲明會(huì)被提升到全局作用域。

第五題

以下代碼輸出什么?

(() => {
  let x;
  let y;
  try {
    throw new Error();
  } catch (x) {
    x = 1;
    y = 2;
    console.log(x);
  }
  console.log(x);
  console.log(y);
})();

答案:1 undefined 2。因?yàn)?code>catch中的x是一個(gè)新的變量,不是外部的x,所以x = 1只會(huì)改變catch中的x,而不會(huì)改變外部的x。而y = 2不是catch的參數(shù),只是在catch中賦值的,所以會(huì)改變外部的y

暫時(shí)性死區(qū) - Temporal Dead Zone

TDZ即Temporal Dead Zone - 中文名暫時(shí)性死區(qū),是指letconst聲明的變量在其作用域開始到變量聲明之間的這段區(qū)域。在暫時(shí)性死區(qū)內(nèi)無(wú)法訪問變量,訪問會(huì)報(bào)錯(cuò)。

function foo() {
  console.log(b); // ReferenceError: Cannot access 'b' before initialization
  let a = 1;
  const b = 2;
}
foo();

對(duì)于以上代碼,常量b的暫時(shí)性死區(qū)開始于函數(shù)的第一行,終止于b的聲明,而console.log(b);這句恰恰在暫時(shí)性死區(qū)內(nèi)訪問了b,所以會(huì)報(bào)錯(cuò)。

面試題

以下代碼輸出什么?

function foo() {
  console.log(typeof bar);
  const bar = 1;
}
foo();

答案:
ReferenceError: Cannot access 'bar' before initialization因?yàn)?code>console.log(typeof bar);這句在bar的暫時(shí)性死區(qū)內(nèi)訪問了bar,所以會(huì)報(bào)錯(cuò)??梢钥吹?,即使強(qiáng)如typeof這種幾乎不會(huì)報(bào)錯(cuò)的操作符也無(wú)法規(guī)避暫時(shí)性死區(qū)。

如果我們把const bar = 1;去掉,那么代碼就不會(huì)報(bào)錯(cuò)。typeof操作符對(duì)于沒有聲明的變量不會(huì)報(bào)錯(cuò),而是返回undefined。

function foo() {
  console.log(typeof bar); // 輸出undefined
}

重新聲明- Redeclaration

  • var聲明的變量可以被重復(fù)聲明,后聲明的覆蓋先聲明的。
  • letconst聲明的變量不可以被重復(fù)聲明。

面試題

看幾道面試題,以下幾段代碼輸出什么?

  • 第一題
var a = 1;
function foo() {
  var a = 2;
  {
    var a = 3;
    console.log(a);
  }
  console.log(a);
}
foo();
console.log(a);

答案:3 3 1, 這個(gè)題主要考察兩個(gè)知識(shí)點(diǎn):

  • var聲明的變量沒有塊級(jí)作用域。
  • var聲明的變量可以被重復(fù)聲明,后聲明的會(huì)覆蓋先聲明的。
    所以var a = 3會(huì)覆蓋外部的var a = 2,但是var a = 2不會(huì)覆蓋最外面的var a = 1。因?yàn)?code>var有函數(shù)作用域。

以上代碼提升后等價(jià)于如下代碼:

var a;
a = 1;
function foo() {
  var a;
  var a; // redeclaration
  a = 2;
  {
    a = 3;
    console.log(a);
  }
  console.log(a);
}
foo();
console.log(a);

注意:面試題中凡事用{}包裹var的都是障眼法,var沒有塊級(jí)作用域。

第二題

這道題比較簡(jiǎn)單,考察的是let的塊級(jí)作用域,代碼輸出2, 1。因?yàn)?code>let有塊級(jí)作用域。let a = 2只在{}內(nèi)有效。

function foo() {
  let a = 1;
  {
    let a = 2;
    console.log(a);
  }
  console.log(a);
}
foo();

意外的全局變量

如果我們聲明變量的時(shí)候忘記了寫varlet或者const,那么這個(gè)變量就是所謂的Accidental Global Variables,意思是意外的全局變量。

function f1() {
  b = 2; // accident global variable
}
f1();
console.log(b); // 2

面試題

以下代碼輸出什么?

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

答案:3 3 3
因?yàn)?code>var沒有塊級(jí)作用域,所以setTimeout內(nèi)的i都是指向同一個(gè)i,而setTimeout是異步的,其回調(diào)函數(shù)代碼需要先進(jìn)入宏任務(wù)隊(duì)列,待for循環(huán)結(jié)束后才能執(zhí)行,此時(shí)i已經(jīng)是3了。關(guān)于這道題的詳細(xì)解釋,請(qǐng)看這篇。

最佳實(shí)踐

  • 如今ES6已經(jīng)普及,對(duì)于業(yè)務(wù)代碼來(lái)說(shuō),基本不需要使用var了,var目前只有JS框架或者底層工具庫(kù)才會(huì)使用。

  • 對(duì)于letconst,優(yōu)先使用const,只有在需要修改變量的情況下才使用let

  • 經(jīng)典for循環(huán)使用let,因?yàn)檠h(huán)變量會(huì)被修改。

    for (let i = 0; i < 5; i++) {
      console.log(i);
    }
  • for...infor...of使用const,因?yàn)檠h(huán)變量不會(huì)被修改。

    const arr = [1, 2, 3];
    for (const item of arr) {
      console.log(item);
    }
    const obj = {a: 1, b: 2};
    for (const key in obj) {
      console.log(key);
    }

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

相關(guān)文章

最新評(píng)論