ES6系列入门学习记录:let和const

195 阅读8分钟

前言

感谢你能点进这篇文章,首先我先做一个说明,我是今年刚毕业的前端应届生,这篇文章是我学习ES6的letconst部分之后,自己做的归纳笔记,也是我的第一篇文章。第一次做这种文章类的分享,而且是在一个大平台上,如果有不足,希望可以帮我点出,十分感谢。

其实在发表文章之前,我们公司前端组的大佬就一直鼓励我去做文章分享,打造自己的一个品牌。但是由于自己性格问题和懒惰,一直在拖。毕竟我最开始并不觉得自己有什么能分享的,但是后续慢慢的才理解到一个真理:分享是没有门槛的。所以开始尝试做这种事情,希望可以慢慢做好,毕竟也是对自己的一种提升和锻炼。之后会继续更新ES6的学习记录文章,文章的内容,都是通过自己理解之后,然后用自己的话语去进行一个描述,当中可能会有不太准确或者不太恰当的描述,也欢迎观看文章的您提出这类的意见和建议。同时我的文章会进行一些内容的验证,有些部分可能会验证的有点多,也请多担待。

最后补充一句,我目前ES6系列学习的主要文献是阮一峰大神的《ECMAScript 6 入门》

那就正式开始吧。

Let命令

let命令用于声明变量,用法类似于var,但是let命令有个特点那就是只会作用在let所在的作用域内。

Let命令的作用域

let a = 1;
{
    var b = 2;
    var c = a;
    let d = 3;
 }
 
 a // 1
 b // 2
 c // 1
 d // ReferenceError: b is not defined

这里的a参数的let命令用法毫无意义,如果这样使用就和var没区别,倒不如说要这样使用还不如使用var

for循环则非常适合使用该命令

for(let i=0;i<1;i++){
   console.log('A',i);
}
console.log('B',i);

// A 0 
// ReferenceError: i is not defined

for循环中使用let命令,每一轮循环的i都是一个新的变量,如果在内部使用计算公式等,则会通过JavaScript引擎记住上一轮循环结果的值,然后对其进行后续的循环计算,总而完成计算。

for(let i = 0;i<3;i++){
  let i = 'a';
  console.log(i);
}

// a
// a
// a

此处是在for循环中使用let时候的一个特点,当子作用域中使用let再次定义了一个与父作用域中相同名称的参数时,两个参数互不干扰。

暂时性死区

只要块级作用域内存在let命令,它所声明的变量就“绑定”这个区域,不再受外部的影响。

let a = 1;
let b = 1;
{
   let a = 2;
   b = 2;
   console.log('a1',a);
   console.log('b1',b);
}
console.log('a2',a);
console.log('b2',b);

// a1 2
// b1 2
// a2 1
// b2 2

当分别在父作用域子作用域内使用let定义参数时,即便参数名相同,他们也不是同一个参数。父作用域中定义的参数,只会作用在自身作用域未重新使用let命令定义同名参数的子作用域中。该情况就是自作用于中的let命令产生了暂时性死区。

var a = 1;
{
    console.log(a)
    let a = 2;
}

// ReferenceError: a is not defined

以上代码可知,作用域内只要使用了let命令声明的参数,即便有同名全局变量,也无法在let命令代码执行之前对该参数进行任意操作,即使这个操作和let命令是属于同一个作用域

let的暂时性死区的特点, 会导致任意作用域,只要某个参数有对应的let声明,无论该声明的位置在哪,该作用域内的该参数,便会完全独立于在该作用域内,不会受到全局或者父作用域中同名参数的干扰。

不允许重复声明

注意一点,let命令是个小贪心鬼,同作用域内不允许有其他同名参数,无论是第二次同名命名是使用var还是let,都会报错。其子作用域中,也必须使用let命令进行同名命名,否则也会报错。

let a = 1;
let a = 2;
console.log(a);

// Identifier 'a' has already been declared
var a = 1;
let a = 2;
console.log(a);

// Identifier 'a' has already been declared
let a = 1;
var a = 2
console.log(a);

// Identifier 'a' has already been declared
var a = 1;
var a = 2;
console.log(a);

//  2
let a = 1;
{
	var a = 2;
	console.log(a);
}
console.log(a);

以上代码若在chrome调试面板测试时,请切记手动改参数名或者清除上一次代码所命名的参数。

Let命令不存在变量提升

所谓变量提升,就是变量可以在声明代码之前使用,不会出现报错,不过值未undefinedvar便有该特点。

console.log(a);
var a = 1;
// undefined

console.log(b);
let b = 1;
// Identifier 'b' has already been declared

使用var命令声明的参数,即会发生变量提升的参数,在脚本开始运行时,对应的变量就已经被创建,直到执行到实际定义参数的代码时,该参数才会被赋上对应的值。

块级作用域与函数声明

概念

在ES5中,一般只有全局作用域和函数作用域。

而在ES6中,增加了一个块级作用域。ES6 规定,块级作用域之中,函数声明语句的行为类似于let,在块级作用域之外不可引用。

一般而言,每个{}内部就是一个块级作用域。

function f() { console.log('I am outside!'); }

(function () {
  if (false) {
    function f() { console.log('I am inside!'); }
  }

  f();}());
  
// Uncaught TypeError: f is not a function

上述代码在ES6环境中执行的时候,会出现报错,因为两次声明的function和执行的f()不在同一块级作用域。

注意点

ES6改变了块级作用域内声明的函数的处理规则,但是由于互联网目前的现状是多个版本环境同时并行的情况。所以ES6有以下规定:

  • 允许在块级作用域内声明函数
  • 函数声明类似于var,即会提升到全局作用域或函数作用域的头部。
  • 同时,函数声明还会提升到所在的块级作用域的头部。

以上规则只对ES6的浏览器生效。在其他环境下不会生效。

综上所述,我们需要尽量避免在块级作用域内声明函数。如果无法避免,也要写成函数表达式。并且块级作用域的声明函数规则,必须在使用{}的情况下使用,不可以使用简写。

if(true) 
    function f() {}
//报错

const命令

概念

const用于声明一个只读的常量。

特点

由于const声明的常量为只读,所以其声明的常量无法修改。

const a = 123;

 a //123
 
 a = 321; // TypeError: Assignment to constant variable.

声明的常量不能再次修改,所以意味着他必须在声明的时候就进行赋值。因为如果不这样做,你的声明就没有意义。

const a; // SyntaxError: Missing initializer in const declaration

constlet相似,只在块级作用域内生效,同时也不提升和存在暂时性死区。

if(true){
   const a = 1;
}

a // ReferenceError: a is not defined


if(true){
   console.log(b);
   const b = 1;
}
//ReferenceError: b is not defined

同时也和let命令一样,在同一块级作用域内,不可重复使用一样的名称,即便一个是声明常量,一个是声明变量。

   var a = 1;
   let b = 1;
   
   const a = 2; // SyntaxError: Identifier 'a' has already been declared
   const b = 2; // SyntaxError: Identifier 'b' has already been declared

本质

const并不是变量的值不可改变,而是变量所指向的那个内存地址所保存的数据不得改变。特别是复合类型的数据,变量指向的内存地址,保存的只是一个指向实际数据的指针,const只能保证指针是固定的。

听起来其实有点绕,我个人的理解是,比如你需要调某个仓库的货物,然后我告诉你仓库的地址,我只能保障那个仓库的位置在那里不变,但是仓库里面放什么我就无法保证了。

const a = {};

a.prop = 1;
a.prop; // 1

因此,使用const声明的时候需要格外小心,不然就是红红的报错了。(虽然快过年了,但是代码还是别增添顾念的气氛了)

一些小补充

顶层对象的属性

在ES5中,顶层对象的属性和全局变量是等价的,也就是说全局变量的a = 1 等同于 window.a = 1

ES6中,为了改变这个情况,给varfunction命令保留了原有的这个特性的同时。也规定了letconstclass等命令所声明的全局变量,不属于顶层对象的属性。

var a = 1;
window.a //1

let b = a;
window.b //undefined

总结

第一篇结束了,一开始写的时候特别乱,然后慢慢调整成了目前这一篇。如果你觉得还可以,希望可以帮点个赞。之后的更新我会继续奉上,也希望能受到你的喜欢和收到你的意见和建议,十分感谢。