ES6的初体验

/ 0评 / 1

深挖概念,挖着挖着我笑了。

体验了一下let和const,真香!

为啥香啊?在我看来,写代码过程中,当用var定义了多个变量时,有时难免出现变量名重复而你根本没发现,然后抓头发,头发抓着抓着就没了🤣如果没有某些方面的改善,let和const也许就不会出现了。


先来说说let和const两兄弟

这俩的出现绝非偶然,就像你人生中遇到的人一样。

let用来声明变量,而const用来声明常量(即不变的值,源自单词constant)。显然地,let代替了var用来声明变量,而const则是新出现的专门用来声明常量的,与var没有任何关系!(有些练习题就喜欢这样下套!)。虽然一个用来代替,一个是新出现的,但两个的用法与var是一样的。


列一下变量与常量的区别吧

变量:可对其重新赋值。

常量:一旦初始化,就不能对其重新赋值。


let没啥好说的,说说const

新出现的关键字,其注意事项有:

1.使用const声明常量时,一旦声明,就必须立即赋值初始化,不能留到以后赋值。

const a;
a = 2;
console.log(a);

如果你这样写,恭喜你,浏览器控制台给你留了一句话:"Missing initializer in const declaration"。因此,使用const进行声明常量时,千万别忘了给它赋值。

2.使用const声明的常量,允许在不重新赋值的情况下修改它的值。

啊?这是什么意思?

其实有两层意思,重点是"不重新赋值"。1.当const声明一个基本数据类型时,如:const sex = 'male'; 你如何在不重新为sex常量赋值的情况下改变sex常量的值?有啥办法呢?答案是:没有任何办法。那你说的这种情况是指啥?说的就是:2.当const声明一个引用数据类型时,如(对象):

const person = {
       name: 'Alex';
};
const person = {};
person.name = 'ZhangSan';

上面两句谁修改的是对的?当然是第二句啰。第一句明显就是给常量对象person赋值了一个空对象,犯了大忌。我们不能给常量对象赋值,难道还不能修改其属性的值啊?显然是可以的。


什么时候用let,什么时候用const?

首先,当清楚自己的需求或者你一眼就能看出是用let还是const(比如循环);当你不清楚需求的情况下,推荐先用const声明,因为在以后需要改变常量的值时,你能看得到错误,不至于用let可能发现不了。


重头戏来啦,开始讲故事了!

我觉得这绝壁是八股文中的一个:let、const、var的区别。区别是什么?有多少个区别?

有5个区别:

  1. 重复声明
  2. 变量提升
  3. 暂时性死区
  4. window对象的属性和方法
  5. 块级作用域

啥叫重复声明啊?

重复声明是指:已经存在的变量或常量,又声明了一遍。var存在重复声明,而let和const不存在。

var i = 1;
......
var i = 2;
console.log(i);

上面的输出i为2,再来看let和const。

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

用let声明时,会出现报错,显示a已经声明过了。

那再来看看这个例子:

function func(a){
      let a = 1;
}
func();

调用函数func时,会出现啥结果呢?仍然是报错,显示a已经声明过了。为啥啊?

因为含义中说的"已经存在"是指<以任何形式存在的变量或常量>,那么函数的形参也算是变量啊,因此会报错。所以在理解重复声明时,要特别注意这个"已经存在"指的是以任何形式存在的变量或常量


啥叫变量提升呢?

其含义是:var会将变量的声明提升到当前作用域的顶部。因此var存在变量提升,而let和const不存在,上栗子:

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

这个会报错吗?还是会输出a的值呀?都不是,这段代码相当于下面的代码

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

看完这两个栗子再加上含义理解理解。咱来说说:

正如下面代码所示,其背后的形式长这样。在上面的代码中,程序开始按顺序执行,console语句执行时,发现程序要它去输出a的值,可console愁呀!前面都没看到a的影子啊,更别提上哪儿去找a的值了。诶,且慢,这时,在它下面的var看到了console的愁容,说:哥们儿,我有超能力啊,我可以让a去你的前面,但这超能力有限,不能让a把它的值也带上。console无语了,想了想这也是个办法,总比让浏览器大哥报错的好啊。于是,var就照办了,谁来都不好使。因此,console只能输出一个未带值的a,于是浏览器无情地告诉咱们:undefined。那咱们就明白了呗,var会将声明的变量提升到当前作用域的顶部,那这个栗子中的作用域是啥?当然是全局作用域啊,难道这里还有啥作用域吗?

变量提升,咱就讲完了。


啥叫暂时性死区啊?这又是啥啊?

别急,咱先说说其含义:只要作用域中存在let、const,它们所声明的变量或常量就会自动"绑定"这个区域,不会再受到外部作用域的影响。因此,let和const存在暂时性死区,而var不存在。

啊?这是啥? 那咱看看下面的栗子呗:

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

别急别急,咱先来捋一捋程序咋样执行的:值得注意的是(只有当函数被调用时,才会生成函数作用域,函数调用结束后,其生成的函数作用域也随之而消亡。)有了这个前提,咱们再来说说:程序执行时,会先略过声明,而是直接执行函数调用(这又是重要的一点:程序执行时会先略过声明!),func函数被调用了,那么它生成了一个函数作用域,在这个函数中,接着执行console语句,诶,你说巧不巧,程序又让console去找a的值,那它咋办嘛,只能是现在当前的函数作用域中找有没有a呀,很可惜,它没找到。这里可能又有人说了:啊?下面不是有a吗?记住:查找是从内部作用域——>外部作用域——>直到全局作用域。因此console没找到a,console苦啊,内部的函数作用域中,它没找到a,在家里竟然都没找到。于是它又只能爬山涉水地往外部作用域走了,但此时!它发现它走不出去了!家里门被锁了!为什么呀?因为它看不到它的家里其实还有一个let声明的变量a!这个let很坏,当它出现在别人家里并声明了一个变量时,它就会把别人家的门给锁了!console麻了呀,到死都出不去,又只能向浏览器报告说自己根本找不到a,浏览器直呼离谱,于是直接向我们报错:a未初始化。也就是说,当一个作用域中出现了let、const,且它们也声明了一个变量,那么这个变量就会自动”绑定“当前作用域,使其不受外部作用域的影响

我们能否先将视线看向变量提升和暂时性死区的代码?能发现什么吗?这些代码的顺序是不是不太正常啊?没错,反观这些栗子以及变量提升和暂时性死区的含义,我们不难得出:这两个名词的出现,不就是提醒我们要养成良好的编程习惯吗?


咱们轻松地聊聊关于window对象的属性和方法

这个完全是对于var来说的。

其含义为:在全局作用域中,var声明的变量,通过function关键字声明的函数,会自动地变成window对象的属性和方法

var age = 18;
function add () {};
console.log(window.age);
console.log(window.add === add);

会输出 18 和 true。

而当let和const声明时

let age = 18;
const add = function () {};
console.log(window.age);
console.log(window.add === add);

会输出 undefined 和 false。

这个没啥好讲的,记住就行。


啥叫块级作用域?怎么又有一个块级作用域啊?

var不存在块级作用域,而let和const存在块级作用域。

先来个栗子看看:

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

哈?我就猜到你会说这是个块级作用域。其实,这里没有啥块级作用域,只存在一个全局作用域。那么此时var声明的就是一个全局变量啦,最终输出为3。

再来看一个栗子:

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

诶?那这次输出的会不会是3呢?很遗憾,也不是。此时let与for循环组成了一个块级作用域。那么,在循环之外的console语句想输出i的值,却找不到,就告诉浏览器没找到,于是浏览器告诉我们:i没有被定义。

谈谈作用域链

由于自己写然后再画作用域时直线不直太丑了,就找了张图。

正如图中所看到的,for循环与let形成了块级作用域,函数被调用之后形成了函数作用域,而全局作用域本身就存在。其实,这顺序在上边中也提到过,查找变量时,是沿着作用域链往外寻找的,也即顺序为:内部作用域——>外部作用域——>......——>直到全局作用域。沿着这个顺序查找就行。


那有哪些块级作用域呢?

大部分{ } 、if(){ }、while(){ }、do{ }while()、for( ){}、switch(){ },这些花括号+let/const = 块级作用域。

尽管function(){ }也有花括号,但它属于函数作用域。

尽管对象也有{},但它不构成任何作用域!

对了,作用域有三个:全局作用域、函数作用域、块级作用域。

ES6,yyds!

发表评论

渝公网安备 50010102001052号

/

渝ICP备2021009595号