ES6中let和const那些事

一、let和const简单用法介绍
1、let和const是什么
let和const是用来声明变量和常量的,之前用的var声明变量,现在let也是用来声明变量的,而const是用来声明常量的,const就是constant的缩写
2、let 和 const 的用法:
let就跟var差不多,例如:

      var username = 'Alex';
      let age = 18;
      const sex = 'male';
      console.log(username, age, sex); // Alex 18 male

什么是变量,什么是常量:

      username = 'ZS';
      age = 28;
      console.log(username, age); // ZS 28
      // 同上,这里的age和username就是变量
	  sex = 'female';  // 在这里会报错,因为sex是常量,一旦被赋值就不能再被改变了

总结:
var、let声明的就是变量,变量一旦初始化之后,还可以重新赋值
const 声明的就是常量,常量一旦初始化,就不能重新赋值了,否则就会报错
二、let和const为何出现:

      // 1.为什么需要 const
      // let
       let sex = 'male';
       // ...
       sex = 'female';
       console.log(sex); // 不会报错

      // const
       const sex = 'male';
       // ...
       sex = 'female';
       console.log(sex); // 这里会报错,因为const定义常量
	   // const 就是为了那些一旦初始化就不希望重新赋值的情况设计的

// 2.const 的注意事项
      // 2.1.使用 const 声明常量,一旦声明,就必须立即初始化,不能留到以后赋值
      const sex;
      sex='male'; // 这样会报错 Missing initializer in const declaration
	  const sex = 'male'; // 这样写才为正确写法!

      // 2.2.const 声明的常量,允许在不重新赋值的情况下修改它的值
      // 基本数据类型
      const sex = 'male';
      sex = 'female'; // 报错!

      // 引用数据类型
      const person = { username: 'Alex' };
      // person = {}; // 一旦再重新赋值即会报错!
      person.username = 'ZhangSan';
      console.log(person); // 不会报错 输出 {username: "ZhangSan"}  // 可以修改值但不能重新赋值
      person = {}; // 报错 原因是进行了重新赋值

      // 3.什么时候用 const,什么时候用 let
// 推荐:
      // 在不知道用let还是const时,推荐先用const

总结:
1、const可以在引用类型的情况下修改里面的值,但一旦const声明的是基本类型则无法修改值。2、在不知道到底用let和const的情况下尽量用const,一是实际开发中基本这样来,二是用const一旦改变值时会报错(这是对人的一个提醒),这样可以根据需求去将const改为let,但如果用的let则不会报错,可能后面对值的改变会影响前面(最重要的是程序没有提醒,人可能不知道)。
三、let和const的区别:
1、重复声明:

      // 已经存在的变量或常量,又声明了一遍
      // var 允许重复声明,let、const 不允许
      let a = 1;
      // ...
      let a = 2;
      console.log(a); // 会报错
      
      function func(a) {
          let a = 1;
       }
      func();
// 会报错,a在函数里面有,故不能再在函数内声明!

2、变量提升:

      // var 会提升变量的声明到当前作用域的顶部
      console.log(a);
      var a = 1;  // 不会报错,可以打印出a
      // 相当于
      // var a;
      // console.log(a);
      // a = 1;
      // console.log(a);

      // let、const 不存在变量提升
      console.log(a); // 会报错,找不到a
      let a = 1; 

这里的没有变量提升,实际上是为了开发者养成良好的编程习惯,对于所有的变量或常量,做到先声明,后使用!
3、暂时性死区:

      // 只要作用域内存在 let、const,它们所声明的变量或常量就自动“绑定”这个区域,不再受到外部作用域的影响
      // let、const 存在暂时性死区
      let a = 2;
      let b = 1;
      function func() {
         console.log(b); // 1
      }
      func();
      // 在这个例子中不会报错,因为函数中没有b,所以会向上找,找到b = 1
      // let、const 存在暂时性死区
      let a = 2;
      let b = 1;
      function func() {
      	console.log(a);
      	let a = 1;
      }
      func();
      // 在这里会报错,原因是a用的let声明的,因此就将a绑定到了函数的作用域内,在该作用域中是先打印a后声明a的,所以会报错!

4、window 对象的属性和方法:

      // var/function
      var age = 18;
      function add() {}
      console.log(window.age); // 18
      console.log(window.add === add); // true
 
      // let/const
      let age = 18;
      const add = function () {}; 
      console.log(window.age); // undefined
      console.log(window.add === add); // false

5、块级作用域:
(1)什么是块级作用域:

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

      // let/const 有块级作用域
      for (let i = 0; i < 3; i++) {
      }
      console.log(i); // 报错 --- i不能被找到 , 这是因外i在{}之外,故不能找到

说到作用域时就不得不提一下作用域链这个事,这个在JS基本方法中有,记住:只能由内往外找不能由外往内找就对了!
(3).有哪些块级作用域:
一般有{}的都有块级作用域:

// 块级作用域:
      {}
      for(){}
      while(){}
      do{}while()
      if(){}
      switch(){}

// 但函数和对象可不是块级作用域
      // function(){}
      // const person = {
      //   getAge: function () {}
      // };
注意:块级作用域是相对let和const而言的,var可没有块级作用域!

简单举例循环中块级作用域中的区别:
目标:当点击相应按钮时会在控制台打印出相应按钮的下标!

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        div{
            margin: 0 auto;
            width: 300px;
            display: flex;
            justify-content: space-between;

        }
        .btn{
            width: 50px;
            height: 50px;
            font-size: 16px;
            text-align: center;
        }
    </style>
</head>
<body>
    <div>
        <button class="btn">0</button>
        <button class="btn">1</button>
        <button class="btn">2</button>
    </div>
    <script>
        var btns = document.querySelectorAll('.btn');
        for(var i=0; i < btns.length; i++){
            btns[i].onclick = function() {
                console.log(i); // 由于不在块级作用域导致每次打印的均为3,而不是相应的下标 0 1 2

// 不打印相应的下标原因很简单,当打印i时,会往外找i,i在全局作用域中且循环完为3,所以打印出来全是3,与作用域有关!
            }
        }
    </script>
</body>
</html>

在上面的案例中,因为函数里面没有i,所以程序就会往外找,因为出了点击事件绑定的函数就是for循环,因为for循环没有作用域,所以相当于在全局里面找i,在全局中i是3,因此打印出来是3
ES6之前的解决方法:
采用闭包的思想,具体代码如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        div{
            margin: 0 auto;
            width: 300px;
            display: flex;
            justify-content: space-between;

        }
        .btn{
            width: 50px;
            height: 50px;
            font-size: 16px;
            text-align: center;
        }
    </style>
</head>
<body>
    <div>
        <button class="btn">0</button>
        <button class="btn">1</button>
        <button class="btn">2</button>
    </div>
    <script>
        var btns = document.querySelectorAll('.btn');
        for(var i=0; i < btns.length; i++){
            (function(index) {
                btns[index].onclick = function() {
                console.log(index);
            }
            })(i);
// 将其放到一个立即执行的匿名函数里面,这种是采用了闭包的思想!
        }
    </script>
</body>
</html>

在这里可以这样理解:打印index就要找到index,在点击事件绑定的函数中没有index,所以就会往外找,于是就到了立即执行函数的作用域,在立即执行函数的作用域里面可以找到index,index就是立即执行函数传进去的参数嘛,因此能找到,所以可以打印出来。
ES6之后的解决方案:
直接将var 改为 let 即可实现:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        div{
            margin: 0 auto;
            width: 300px;
            display: flex;
            justify-content: space-between;

        }
        .btn{
            width: 50px;
            height: 50px;
            font-size: 16px;
            text-align: center;
        }
    </style>
</head>
<body>
    <div>
        <button class="btn">0</button>
        <button class="btn">1</button>
        <button class="btn">2</button>
    </div>
    <script>
        let btns = document.querySelectorAll('.btn');
        for(let i=0; i < btns.length; i++){
            btns[i].onclick = function() {
                console.log(i); // let有块级作用域,相当于创建三个空间,分别是 0 1 2 这三个事件
            }
        }
    </script>
</body>
</html>

let图解

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值