玩命加载中 . . .

var let const 的区别使用


var

用于声明变量,变量声明的同时,可以赋值也可不赋值(不赋值的情况下,变量会保存一个特殊值 undefined ),后续可以更改变量的值。

  • 注意1:
    • 变量名可以包含字母,数字,下划线和美元符号,但要以字母开头【也可以以$和_开头(但一般不这么用)】。
    • 变量名是大小写敏感的(y和Y是不同的变量)
    • 保留字(如JavaScript关键字)不能作为变量名使用
  • 注意2:var会发生“变量提升”现象。
    function foo () {
      console.log(age);
      var age = 20;
    }
    foo(); // undefined
    之所以不会报错,是因为 ECMAScript 运行时把它看成等价于如下代码:
    function foo () {
      var age;
      console.log(age);
      age = 20;
    }
    foo(); // undefined
    这就是所谓的“变量提升”,也就是把所有变量声明都拉到函数作用域的顶部。此外,反复多次使用 var 声明同一个变量也没有问题:
      function foo () {
        var age = 20;
        var age = 25;
        var age = 30;
        console.log(age);
      }
      foo(); // 30
    ### var 声明作用域
    使用 `var` 操作符定义的变量会成为 包含它的函数的局部变量。比如,使用 `var` 在一个函数内部定义一个变量,就意味着该变量将在函数退出时被销毁:
    ```js
    function test () {
      var message = 'hi';  // 局部变量
    }
    test();
    console.log(message);  // 出错!
    这里,message 变量是在函数内部使用 var 定义的。函数为 test() ,调用它就会创建这个变量并给该变量赋值;调用之后变量随即被销毁,因此实例中的最后一行会导致错误。
    不过,在函数内定义变量时省略 var 操作符,可以创建一个全部变量。
    function test () {
      message = 'hi';  // 全局变量
    }
    test();
    console.log(message); // "hi"
    去掉之前的 var 操作符之后,message 就变成了全局变量。只要调用一次函数 test() ,就会定义这个变量,并且可以在函数外部访问到。

    注意:虽然可以省略 var 操作符定义全局变量,但不推荐这么做。因为在局部作用域中定义的全局变量很难维护,也会造成困扰。在严格模式下,如果像这样给未声明的变量赋值,则会导致抛出 ReferenceError

let

它的用法类似于var,但是所声明的变量,只在 let 命令所在的代码块内有效。 看下面例子:

if (true) {
  var name = 'hg';
  console.log(name); // hg
}
console.log(name); // hg

if (true) {
  let age = 20;
  console.log(age); // 20
}
console.log(age); // ReferenceError:age 没有定义

在这里,age 变量之所以不能再 if 块外部被引用,是因为它的作用域仅限于该块内部。
由于块作用域是函数作用域的子集,因此适用于 var 的作用域限制同样也适用于 let 。

  • 注意1:let不允许在相同作用域内,重复声明同一个变量。
      // 报错
      function() {
        let a = 10;
        var a = 1;
      }
      // 报错
      function() {
        let a = 10;
        let a = 1;
      }
      // 报错
      function func(arg) {
        let arg; 
      }
    
      // 不报错
      function func(arg) {
        {
          let arg; 
        }
      }
      ```     
    - 注意2:let不像var那样会发生“变量提升”现象。
    
    ## const
    **声明一个只读的常量。一旦声明,常量的值就不能改变;且声明变量时,就必须立即初始化,不能留到以后赋值。**
    - 注意1:`const` 的作用域与 `let` 命令相同:只在声明所在的块级作用域内有效。
    - 注意2:`const` 命令声明的常量也是不提升,只能在声明的位置后面使用。
    - 注意3:`const` 声明的常量,也与 `let` 一样不可重复声明。
    - 注意4:对于复合类型的变量,变量名不指向数据,而是指向数据所在的地址。`const` 声明的限制只适用于它指向的变量的引用。**const 命令只是保证变量名指向的地址不变,并不保证该地址的数据不变,也就是说,如果 const 变量引用的是一个对象,那么修改整个对象内部的属性并不违反 const 限制。**   
        栗子1:
        ```js
        const foo = {};
        foo.prop = 123;
        console.log(foo.prop); // 123
        foo = {}; // TypeError:"foo" is read-only
    
        // 上面代码中,常量foo储存的是一个地址,这个地址指向一个对象。不可变的只是这个地址,即不能把 foo 指向另一个地址,但对象本身是可变的,所以依然可以为其添加新属性。  
    栗子2:
    const a = [];
    a.push('Hello'); // 可执行
    a.length = 0;    // 可执行
    a = ['Dave'];    // 报错
    
    // 上面代码中,常量 a 是一个数组,这个数组本身是可写的,但是如果将另一个数组赋值给 a ,就会报错。

变量提升

关于变量提升,还有一些东西可以探讨一下。首先,变量提升是指把变量声明提升到当前执行环境的最顶端。

看一个例子:

console.log(foo); // 输出undefined
console.log(bar); // 报错ReferenceError

var foo = 2;
let bar = 2;

// 以上代码可看作:
var foo;
console.log(foo); // undefined
console.log(bar); // 报错ReferenceError
foo = 2;

let bar = 2;

上面代码中,由于 var 发生了“变量提升”现象,将 foo 的声明提升到了 console.log(foo) 前面,即脚本开始运行时,变量 foo 已经存在了,但是没有值,所以会输出 undefined
变量 bar 用 let命令声明,不会发生变量提升。这表示在声明它之前,变量bar是不存在的,这时如果用到它,就会抛出一个错误。

优先级

  1. varfunction 的变量提升是有优先级的,且 function 的高于 var 的。(另外,如果函数名字相同,后面函数会覆盖前面的函数。)
    var a;
    function a() {};
    console.log(a) // ƒ a() {}
    
    // 可以隐式地理解为:
    function a() {};
    var a;
    console.log(a); // ƒ a() {}
  2. 当遇到函数和变量同名且都会被提升的情况,由于函数声明优先级比较高,因此变量声明会被函数声明所覆盖,但是可以重新赋值。
    alert(a); // 输出:function a(){ alert('我是函数') }
    function a() { alert('我是函数') }
    var a = '我是变量';
    alert(a);   //输出:'我是变量'
    
    // 上面代码可以隐式的理解为:
    function a(){alert('我是函数')} 
    var a;    // undefined
    alert(a);    //输出:function a(){ alert('我是函数') }
    a = '我是变量';//赋值
    alert(a);   //输出:'我是变量'
  3. var 和 function 的变量提升优先级显而易见,但如果是函数声明 function foo(){} 和函数表达式 var foo = function(){} 呢?
    console.log(f1) // function f1(){}
    console.log(f2) // undefined
    var f2 = function() {} // 函数表达式
    function f1() {} // 函数声明
    上面的代码并不是说函数声明的提升优先级高于函数表达式,而是因为当遇到函数表达式的时候,首先会将关键字+变量名提升到当前执行环境的最顶端,也就是var f2 先被提升,然而此时 f2 的值为 undefined,所以 f2 打印值为 undefined

文章作者: hcyety
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 hcyety !
评论
  目录