ES6笔记( 一 )- let & const

目录:

  1. 使用var声明变量的原罪
  2. 使用let和const声明变量

使用var声明变量的原罪

  1. 定义的全局变量存入window, 如果同名将直接影响window的成员
console.log('test');
var console = 'helloWorld';

console.log('demo'); // 直接报错, 因为上面定义的console
  1. 允许重复的变量声明, 导致影响数据被覆盖
var foo = function() {
    console.log('我是foo函数');
}

// 这里省略1000行代码

// 协同开发的小伙伴不知道我定义过foo这个变量, 于是他也来一次
var foo = 123;

// 这个时候我再去调用foo执行, 肯定是走不掉了
foo(); // 报错
  1. 变量提升, 导致奇怪的闭包问题和逻辑问题
// 2. 变量提升, 怪异的数据访问

if( 1 > 2 ) {
    var a = 20;
}else {
    console.log(a); // undefined
}

console.log(a);  // undefined

// 上面的代码逻辑是, 如果1 > 2 我就声明一个a = 20, 如果1不大于2我们就进else判断去输出a, 这个逻辑是不是有问题, 我肯定是会进else判断的, 我a都声明我去哪打印a呢, 打印就算了他还不给你报错, 无论是代码逻辑还是最终的输出效果都是让人无语

使用let和const声明变量的特点

  1. let和const声明的全局变量不会放入window下, 而是放入全局作用域的scope中
// window全局
let number = 100;
console.log(window.number); // undefined

// 如果我们想看到number存在哪, 可以这样操作
function foo() {
    return function() {}
}

let result = foo();
console.log(result); // 我们知道result是闭包出来的, 所以我们可以查看result的作用域链

执行结果如下, 我们看到在scope域中存储了script对象( 其中包括我们声明的a和后来的result ), 来表示let和const在全局声明的变量

在这里插入图片描述

  1. let和const声明的变量不允许在同一作用域范围内进行同变量名的重复声明
let number = 100;

function foo() {} 

let number = 200; // 这一句会直接报错
  1. let和const声明的变量不会执行变量提升( 其实本质上是因为在全局下也开启了暂时性死区, 暂时性死区在第五点有介绍 )
console.log(a); // 输出undefined
console.log(b); // 直接报错
var a = 100;
let b = 200;
  1. const声明的变量一旦声明就不可进行修改, 也意味着const在声明变量的同时必须进行变量赋值
const a; // 直接报错必须声明就赋值
let c = 200;
c = 300;
const a = 100;
a = 20; // 直接报错, const声明的变量将不允许修改
  1. let和const会开启块级作用域, 在块级作用域中, let和const会接管整个作用域, 所以在特定情况下会发生暂时性死区的情况

暂时性死区: 通过let和const声明的变量也会进行变量提升, 不过变量提升是放进了一个叫暂时性死区的存储空间, 同时如果访问的变量位于暂时性死区的这块空间, 则会报错, 当然, 当代码运行到变量声明语句时, 相应的变量会从暂时性死区中移除

let foo = 123;
var demo = 456;
{
    console.log(demo); // 输出456
    console.log(foo); // 直接报错
    let foo = 234;
    var demo = 567;
}

关于let和const的最佳实践

  • 如果环境允许, 在开发中能够用let和const就不要使用var, 因为通过上方的比对, let和const处理了js的很多毛病, 能够帮助我们在开发中踩更少的坑

  • 在计算机底层中, 查const声明的变量的速度略微快于查let和var声明的变量速度, 所以能够使用const就尽量用const

  • const在企业级开发中会用来声明从字面上来看就绝不可能变化的常量( 绝不可能变化的常量就是一旦定义了就不会确信永远不能更改的数据, 比如圆周率 ), 且常量的书写方式一般是全大写, 单词间用下划线隔开

const PI = 3.14; // 定义圆周率
  • const 声明的常量本质上代表的是常量声明的内存地址不可变, 如果内存地址为一个引用值, 则引用值中的值是可以进行变化的
const arr = [1, 2, 3];
arr[0] = 'helloWorld';
console.log(arr); // ['helloWorld', 2, 3]
  • const声明的变量不可以用在循环体中, 因为循环体虽然在let( 稍后一点会介绍到 )会进行循环变量的映射, 但他本质上的i++还是再操作同一个i, 只是等于用let创建了一个新的i跟每一次循环变量同值在循环体内部而已, 而const如果i++就会报错, 但是在for…in循环中可以使用const, 因为for…in每次都是创建的一个新的循环变量
const obj = {
    a: 10,
    b: 20
}
for(const prop in obj) {
    console.log(obj[prop]);
}

const arr = [1, 2, 3];
for(const i = 0; i < arr.length; i++) { // 直接报错
    console.log(arr[i]);
}

这一条如果你觉得不太好理解你就混个脸熟, 因为笔者也想不出太好的方法来表达, 文字不够生动, 但是随着未来你的开发经验的加强, 你一定会了解和顿悟的

  • 因为let生成的块级作用域, 所以他可以解决一道经典面试题

给10个li分别绑定点击事件, 并输出他们的索引 ( 在过去我们一般使用闭包解决 )

在常规的for循环中, var声明的变量会直接提升到全局, 而let大家可能会认为也是这样, 但是实际上ES6在for循环中对let进行了特殊的处理, 当我们在for循环中使用let的时候, let声明的循环变量会被映射进进入for循环每一项的块级作用域中, 且在循环结束以后, 循环变量会被销毁

// 假设页面中有10个li, 我们都获取到了
let lis = document.querySelectorAll('li');

// 只要在这里使用let, 生成块级作用域, 就可以解决每次输出都是11的问题
// 因为之前这个问题的本质就是10个点击事件的处理函数对应了一个全局变量i
// 而使用let以后10个处理函数都是对应自己独一无二的i了, i不会被放入全局而是放入独一无二的域
for(let i = 0, len = lis.length; i < len; i++) {
    lis[i].onclick = function() {
        console.log(i);
    }
}

console.log(i); // 直接报错

只用将for循环的var改成let就可以解决这道经典面试题了

猜你喜欢

转载自blog.csdn.net/weixin_44238796/article/details/107573591