声明变量关键字汇总

  1. JavaScript 中,一共存在 3 种声明变量的方式:varletconst
  2. 之所以有 3 种方式,这是由于历史原因造成的,最初声明变量的关键字就是 var ,但是为了解决作用域的问题,所以后面新增了 letconst 的方式;

var 关键字

变量提升

  1. 在栈内存(作用域)形成,JS 代码自上而下执行之前,浏览器会把所有带 「VAR」「FUNCTION」 关键字进行提前声明或者定义;

    1. 声明(declare): var a (默认值是 undefinedfunction sum (值是 16 进制堆内存地址);
    2. 定义(defined): a = 12 (定义其实就是赋值)
  2. 变量提升只发生在当前作用域

    1. 加载页面的时候只对全局作用域下的变量进行变量提升,因为此时的函数中存储的都是 代码字符串 而已;
    2. 在全局作用域下、私有作用域下声明的函数或变量(带 VARFUNCTION 的才是声明);
    3. 浏览器很懒,做过的事情不会重复执行第二遍 (当代码遇到创建函数代码,直接跳过,因为在变量提升阶段已经 声明并定义 了)
    4. ES3/ES5 规范: 只有全局作用域和函数执行的私有作用域(栈内存),其他花括号不会形成栈内存;

带不带 VAR 的区别

  1. 全局作用域

    1. 带 var (本质是变量):在全局作用域下声明一个变量也相当于给 window 设置了一个属性,属性值为变量值,在变量提升阶段,就已经把变量设置成 window 的属性了(let 声明的变量不会给 window 设置该属性),全局变量修改 window 属性也修改,反之同样修改;
    2. 不带 var:本质是 window 下的属性,a = 12 相当于 window.a = 12
  2. 私有作用域

    1. 带 var (本质是变量):私有作用域带 var ,变量提升阶段,都声明为私有变量,和外界没有任何的关系;
    2. 不带 var:会向上级作用域查找,查看是否是上级的变量,若不是则一直查找到 window 为止,如果 window 也没有,相当于给 window 设置了一个属性(作用域链);

变量提升的几种情况

  1. 函数表达式:只对等号左边进行变量提升

    // 普通函数由于关键字是 "function",所以在变量提升时,进行了声明和定义(赋值)
    // 函数表达式由于关键字是 "var",所以在变量提升时,只进行了声明,默认值为 undefined
    
    sum();// 2
    fn();// fn is not a function
    
    //匿名函数(函数表达式)
    var fn = function () {
        console.log(1);
    }
    //普通函数
    function sum() {
        console.log(2);
    }
    
  2. 条件判断下的变量提升

    1. 在当前作用域下,不管条件是否成立都要进行变量提升;
    2. var 的还只是声明;
    3. function 的新版本浏览器中 (谷歌 45 之后),在条件判断中的函数,不管条件是否成立,都只先声明,类似 var
    //变量提升: fn (此处不考虑老版本浏览器)
    console.log(fn);//输出 undefined
    
    if (1 === 1) {
        // 输出 fn 函数本身
        // 当条件成立,进入到判断体中(es6中它是一个块级作用域),第一件事并不是执行代码
        // 而是类似于变量提升,先把 fn 声明和定义了,也就是判断体中代码执行之前,fn 就已经赋值了
        console.log(fn);
        function fn() {
            console.log('ok');
        }
    }
    
    //上面判断成立,fn 定义成功,则输出 fn 函数本身,判断不成立则输出 undefined
    console.log(fn);
    
  3. 变量提升下的重名问题

    1. varfunction 关键字声明相同的名字,这种也是重名了;
    2. 关于重名的处理: 如果名字重复了,不会重新声明,但是会重名定义(赋值),不管是变量提升阶段还是代码执行阶段皆是如此;
    fn();//输出 4
    function fn() { console.log(1); }
    
    fn();//输出 4
    function fn() { console.log(2); }
    
    fn();//输出 4
    
    var fn = 100;//fn在此处开始定义(赋值),fn=100;
    
    fn();//100()报错: TypeError: fn is not a function
    function fn() { console.log(3); }
    
    fn();
    function fn() { console.log(4); }
    fn();
    

let 关键字

const 关键字

特点总结

var 关键字

  1. 没有块级作用域的概念

  2. 有全局作用域、函数作用域的概念

  3. 不初始化值默认为 undefined

  4. 存在变量提升

  5. 全局作用域用 var 声明的变量会挂载到 window 对象下

  6. 同一作用域中允许重复声明

let 关键字

  1. 有块级作用域的概念

  2. 不存在变量提升

  3. 暂时性死区

  4. 同一块作用域中不允许重复声明

const 关键字

  1. let 特性一样,仅有 2 个差别

  2. 区别 1:必须立即初始化,不能留到以后赋值

  3. 区别 2:常量的值不能改变

面试题

第 1 题:输出 0-9

// 第一种
for (var i = 0; i < 10; i++) {
  // 每一轮都生成一个自执行函数,形成全新的执行上下文 EC
  // 并且把每一轮循环的 i 当做实参传给私有 上下文中的私有变量 i(形参变量)
  // 定时器触发执行用到的 i 都是私有 EC 中的保留下来的 i
  // 充分利用闭包的保存机制(闭包有保护和保存 2 个机制)来完成的,这样处理不太好,     
  //循环 多次就会产生多个不销毁的 EC
  ~function (i) {
    setTimeout(function () {
        console.log(i);
    }, 10);
  }(i);
}

// 第二种
// let 存在块级作用域,var 没有
for (let i = 0; i < 10; i++) {
  // 形成了 10 个块级作用域,每个块级作用域中都有一个私有变量 i
  setTimeout(function () {
    console.log(i);
  }, 10);
}

let const var 的区别?什么是块级作用域?如何用?

let const var 的区别?

  1. var 定义的变量,没有块的概念,可以跨块访问, 不能跨函数访问,有变量提升;
  2. let 定义的变量,只能在块作用域里访问,不能跨块访问,也不能跨函数访问,无变量提升,不可以重复声明;
  3. const 用来定义常量,使用时必须初始化(即必须赋值),只能在块作用域里访问,而且不能修改,无变量提升,不可以重复声明;

什么是块级作用域?

  1. 最初在 JS 中作用域有:全局作用域、函数作用域,没有块作用域的概念;
  2. ES6 中新增了块级作用域,块作用域由 { } 包括,if 语句和 for 语句里面的 { } 也属于块作用域;

如何用?

  1. 在以前没有块作用域的时候,在 if 或者 for 循环中声明的变量会泄露成全局变量;其次就是 { } 中的内层变量可能会覆盖外层变量;
  2. 块级作用域的出现解决了这些问题;
打赏作者
您的打赏是我前进的动力
微信
支付宝
评论

中午好👏🏻,我是 ✍🏻   疯狂 codding 中...

粽子

这有关于前端开发的技术文档和你分享。

相信你可以在这里找到对你有用的知识和教程。

了解更多

目录

  1. 1. 声明变量关键字汇总
  2. 2. var 关键字
    1. 2.1. 变量提升
    2. 2.2. 带不带 VAR 的区别
    3. 2.3. 变量提升的几种情况
  3. 3. let 关键字
  4. 4. const 关键字
  5. 5. 特点总结
    1. 5.1. var 关键字
    2. 5.2. let 关键字
    3. 5.3. const 关键字
  6. 6. 面试题
    1. 6.1. 第 1 题:输出 0-9
    2. 6.2. let const var 的区别?什么是块级作用域?如何用?