javaScript 中的var,let,const

145 阅读4分钟

ECMAScript 中有3个关键字可以声明变量,var,const 和let。其中,var 在ECMAScript 的所有版本中都可以使用,而const 和let 只能在ECMAScript6 及更晚的版本中使用。

var 关键字

(1)var 声明作用域

在函数外声明的变量的作用域是全局作用域。全局都可以访问。

     var message = "test";

      function test() {
        console.log(message);
      }
      test();//test
      console.log(message);//test

在函数内部声明的变量的作用域是函数作用域。只能在函数内部访问。

      function test() {
        var message = "test";
        console.log(message); //test
      }
      test();
      console.log(message); // process.html:16 Uncaught ReferenceError: message is not defined

在函数内部省略var 关键字声明的变量的作用域是全局作用域。全局都可以访问。

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

(2)var 作用域提升

使用var 关键字声明的变量会自动提升到函数作用域的顶部,这个过程叫作用域的提升。

      function foo() {
        console.log(message);
        var message = "hello world";
      }
      foo(); // undefined

不报错的原因是ECMADScript 运行时会把他看成等加于如下的代码

      function foo() {
        var message;
        console.log(message);
        message = "hello world";
      }
      foo(); // undefined

反复多次声明同一个变量也没有问题

      function foo() {
        var age = 16;
        var age = 36;
        var age = 26;
        console.log(age);
      }
      foo(); //26

let 关键字 与var 关键字的区别

区别一:

let 关键字与var 关键字最明显的区别是,let 声明的范围是 块作用域,而var 声明的范围是函数作用域。

    if (true) {
        var name = "wang";
        console.log(name);
      }
      console.log(name);
      if (true) {
        let age = 26;
        console.log(age);
      }
      console.log(age);

截屏2022-07-05 下午5.40.34.png

name 是使用var 声明的所以在该段代码的整个作用域中都可用,该段代码可能在全局作用域中,或者在函数作用域中。age 是使用let 关键字声明的变量,作用域是块级作用域,出了{},就不能再访问。

区别2:

let 关键字不允许在同一作用域中存在重复声明,也不允许在同一作用域中有与var 关键字同名的变量。但是var 关键字允许。

var name;
var name;
let name;
let name;//Uncaught SyntaxError: Identifier 'name' has already been declared
var name;
let name;//Uncaught SyntaxError: Identifier 'name' has already been declared

区别3:暂时性死区

let 关键字声明的变量不会在作用域中被提升。

    console.log(name);//undefined 存在作用域提升
    var name = 'Matt'
    conslog.log(age);//ReferenceError: age没有定义 ,没有作用域提升。
    let age = 36; 

在解析代码时,JavaScript 引擎也会注意出现在块后面的let 声明,只不过在此之前不能以任何方式来引用未声明的变量。在let 声明前的执行瞬间被称为“暂时性死区“,在此阶段引用任何后面才声明的变量都会抛出ReferenceError。

区别4:全局作用域

与var关键字不同,使用let 在全局作用域中声明的变量不会成为window对象的属性,而var 关键字声明的变量则会成为window 的对象的属性。

    var name = "wang";
    console.log(name); // wang
    console.log(window.name); // wang

    let age = 26;
    console.log(age); // undefined

区别5: for 循环中的let

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

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

在退出循环时,var 关键字中迭代变量保存的是导致循环退出的值:5.在之后执行超时循环时,所有的i都是同一个变量,因而输出的都是同一个最终值。
而使用let 声明迭代变量时,JavaScript 引擎后台会为每个迭代循环声明一个新的迭代变量。每个setTimeout引用的都是不同的变量实例,所以console.log输出的是我们期望的值,也就是循环执行过程中每个迭代变量的值。

const 声明

const 的行为与let 基本相同,唯一一个重要的区别是用它声明的变量必须同时初始化变量,且尝试修改const 声明的变量会导致运行时错误。

const age = 26;
age = 36;//TypeError:给常量赋值。

const 也不允许重复声明

const name = "wang"
const name = "li"

const 声明的作用域也是块

const name = "wang"
if(true){
    const name = 'li'
}

console.log(name);//wang

const 声明的限制只适用于它指向的变量的引用。换句话说,如果const变量引用的是一个对象,那么修改这个对象内部的属性并不违反const的限制。

const person = {}
person.name = "wang" // ok

声明变量的最佳实践

1.不使用用var

2.const 优先,let 次之