SKT-otto

导航

ES6基础


1. ECMAScript介绍


1.1 ECMAScript是什么?
很多初学者都很困惑,ECMAScript是什么?它跟JavaScript有什么关系?之前我们学习JavaScript的时候有说过,js是由三部分组成,分别是ECMAScript,BOM,DOM,可见ECMAScript是js的组成部分,js没有了它可是不行的。
再举个栗子,javascript语法中是区分大小写、变量是弱类型的、结尾的分号可有可无、括号表示代码块等等,为什么会有这样的规定?因为这些全都是ECMAScript规定的,我们都要按照它的规定来做。
就好比我们中学写作文(理科生的痛),内容你可以自己发挥,但是写作规范要统一,用“,”代表逗号,“!”代表感叹号,“......”代表省略号,段落开通要空两格。此外,如果你要写信,就要遵守写信的格式一样,开头要有称呼:“尊敬的xxx”,这就是写作的格式规范!
如果没有了ECMAScritpt,就好比写作文的时候,内容再精彩,但是整篇文章标点符号胡编乱造,改卷老师也不会给你好的分数,甚至看不懂作文的意思。
ECMAScript就是JavaScript中的语法规范!
ECMAScript是属于国际标准化的语言,所有浏览器开发商都要按照它制定的标准来开发浏览器。开发者也一样,按照它的规定来编程代码。


1.2 ECMAScript作用?
我们现在就知道了,ECMAScript是JavaScript的组成部分,它很重要,它还有其他作用吗?有的,它还定义了很多重要的东西,比如:语法---解析规则,关键字,语句,声明,操作等;类型---布尔,数字,字符串,对象等;原型和继承;内置对象和函数的标准库---JSON,Math,数组方法,对象内省的的方法等;
了解了ECMAScript之后,那什么是ES6呢?ES6是ECMAScript 6的缩写简称,这个好理解。顾名思义,它是ECMAScript的第6个版本,也就是说它有更早的版本,以后还会有更多版本。


1.3 ECMAScript历史?
我们大概地了解一下ECMAScript的历史。
1996 年 11 月,Netscape 公司,决定将 JavaScript 提交给国际标准化组织 ECMA。次年,ECMA发布 ECMAScript。这个版本就是 ECMAScript 1.0 版。
1998 年 6 月,ECMAScript 2.0 版发布。
1999 年 12 月,ECMAScript3.0 版发布,成为 JavaScript 的通行标准,得到了广泛支持。
2007 年 10 月,ECMAScript4.0 版草案发布,对 3.0 版做了大幅升级,但是,以 Yahoo、Microsoft、Google为首的大公司,反对 JavaScript 的大幅升级,主张小幅改动,各方分歧太大,争论过于激进,ECMA 开会决定,中止 ECMAScript 4.0 的开发
2009 年 12 月,ECMAScript5.0 版正式发布。
2015 年 6 月,ECMAScript 6 正式通过,成为国际标准。

对于很多开发者来说,ES6带来的新功能涵盖面很广,还有很多很便利的功能等(如:箭头的功能和简单的字符串插值,不懂没关系,后续陆续介绍),确实令人兴奋。


2. ES6新增用法
2.1 Let关键字的用法
我们平时在写代码的时候,用var来声明一个变量,除此之外,好像也没用其他的关键字了,不管我们声明的是字符串类型、数组类型还是数字类型等,都用一个var 搞定(因为JavaScript拥有动态类型),很方便。但现在,ES6告诉你,除了var,不妨试试用let来声明变量试试看。
用var的不足之处一:


看代码,不难猜测代码的意图是想给数组a的元素赋值,每一个元素是一个函数,运行后弹出相对应的数字,比如:运行arr[8]();想alert出一个数字8,运行arr[1](); 想alert出一个数字1,依次类推。但是结果并不是我们预想的那样。运行后实际弹出的是10;不管你运行的是arr[8]还是arr[5],或者是数组内的其他元素,都是alert出一个数字:10。但这并不是我们想要的。至少目前我们可以知道了这是var不足的地方。
用let替换var后,我们再看看:



对比一下两段代码,唯一的不同之处就是循环的时候初始化变量 i 是使用let,而不是用var,运行arr[8]()后确实弹出了数字8;如果运行的是arr[3](),就会弹出数字3;这才是我们的本意,总算实现了,感谢上帝,感谢ES6,感谢let关键字!

为什么用let就可以,用var就跑偏了呢?这是因为let声明的变量仅仅在自己的块级作用域起作用,出了这个块级作用域就不起作用。就好比,小明在国内考的“高级程序员”证,去到国外应聘,别人就不承认你的文凭了,小明只能乖乖待在国内持证上岗。而let声明的变量也一样,出不了自己的块级作用域。

那么,什么是块级作用域,怎么才算一个块级作用域?

任何一对花括号(这玩意:{ })中的语句都属于一个块,在花括号里面用let定义的所有变量在花括号外都是不可见的,我们称之为块级作用域。
怪不得小明的证件去到美国没法使用了,人家认为它的证件“不可见“,就是没这回事,不承认你的证。回到代码中,for循环含有有{ },也就是含有了块级作用域,每个变量 i 都只是在自己的作用域起作用,例如:第10次循环中的 i 的值不会影响到到第9次循环。
如果用var声明的变量,就不是这种情况了, 等循环完后 i 等于10,所有块的i都变成了10了。这就是为什么第一段代码运行后会弹出数字10了,这并不是我们想要的。
就好比小明陆陆续续去了10个国家玩,每到一个国家都给自己弄了一个不同的身份,但是小明被告知以后只能用在第10个国家取得的那个身份,那么之前9个国家认识小明的朋友都会不认识他的,小明当场就懵逼了。

用var的不足之处二:


很多人可能认为:代码一开始已经定义了变量a,值为1,相当于全局变量,代码运行的时候会先弹出这个全局变量a的值:1;然后再重新给a赋值为2;可偏偏又事与愿违,心好累啊,它会告诉你结果是undefined; undefined就是未定义啊,为什么会是未定义呢?
原因就在于我们在代码块(函数内)里面还声明并定义了一个变量a,导致变量提升了,实际的代码执行顺序是这样的,往下看你就知道什么叫变量提升了。



对比一下两段简短的代码:var a = 2; 这句代码被拆分成两部分:声明var a ; 和 定义a = 2;而声明部分被提升(看到了吗?提升两个字出现了)到了代码块的前面,运行的时候自己挪到前面了,这就是“变量提升“,结果就是:先执行声明,接着就执行alert(a);变量a只是声明还没定义,就弹出了undefined了。所以,归根结底就是“变量提升“在作怪。这就是var的又一大不足之处。那么,用let关键字在代码块就不会被提升了吗?是的,不提升了。



用let关键字来定义a;这样a在代码块内就不会提升了。那为什么又报错了呢,因为用let声明的变量,在其块级作用域内是封闭的,是不会受到外面的全局变量a影响的,并且要先声明再使用,所以a的值即不是1(因为不受外面的影响),也不是undefined(因为先声明后使用),更不是2,未声明定义就使用,只有报错啦。

let确实能弥补一些var的不足之处。那么使用let的时候还有什么要注意的吗?
注意1:同一个块级作用域内,不允许重复声明同一个变量。
错误示范一:


错误示范二:


注意2:函数内不能用let重新声明函数的参数
错误示范:


say()函数内用let重新声明了word这个参数,会报错的,一定不要这么做。

let 总结:1.let具有块级作用域 2.let 不会进行变量提升
注意:1.未声明使用会报错 2.不允许有重复的变量名 3.函数内不允许声明与形参相同的变量名

2.2 Const关键字的用法
const是constant(常量)的缩写,const和 let一样,也是用来声明变量的,但是const是专门用于声明一个常量的,顾名思义,常量的值是不可改变的。以前用var声明的变量,想怎么改就怎么改,同一个变量,后面的值可以轻松覆盖原来的值,这次const声明的变量,可由不得我们这么任性地想改就改了。
常量的特点:
1. 不可修改


2. 只在块级作用域起作用,这点与let关键字一样。


3. 不存在变量提升,必须先声明后使用,这点也跟let关键字一样。


4. 不可重复声明同一个变量,这点跟let也一样。


5. 声明后必须要赋值





常量是对象的情况:
先看一段下面代码:



怎么常量Person好像被修改了,name改成了“李四”,而且还添加了age属性,值为20;怎么没有报错,还正常输出,这是什么情况呢?我们一起来找下原因。
这个时候,我们先引入一个概念:在赋值过程中,我们可以分为传值赋值和传址赋值。这里我们用到了传址赋值,什么叫传址赋值?
传址:在赋值过程中,变量实际上存储的是数据的地址(对数据的引用),而不是原始数据或者数据的拷贝。
如果看不懂上面这段话,没关系的,看段代码:



为什么student2的name改成了“李四”,student1的那么也变成了“李四”呢?这就是传址赋值!
怎么理解传址赋值?就好比,你预约了一个装修工(张师傅)到你家进行装修,你把你家的地址告诉了他,他顺着地址来到你家,按照你的要求,把你家的门弄成红色。
仅仅过了两天,你觉得不好看,你又找了另一个装修工(王师傅),你也把地址告诉他,王师傅来到后也是按照你的要求,把门弄成了绿色。
最后,不管是张师傅还是王师傅,通过这个地址来到你家的时候,看到的门肯定是绿色的,因为最后一次修改是改成绿色。


仔细对比一下,这段代码和上一段小代码的结构一模一样(往上翻一下看看),这就知道为什么student2改了name,student1也被修改了。
讲完传址赋值,回到我们的const关键字,用const来声明一个对象类型的常量,就是传址赋值。而不可修改的是对象在内存中的地址,而不是对象本身(不可变的是你家的地址,而不是你家的门)。所以,这就很好的解释刚刚的这段代码为什么不会报错,而是正常输出了。


因为修改的只是Person本身,修改的是name属性和增加一个属性age,而地址没变,也不可变,所以并没有违背常量不可修改的约定。
但是,如果这样写呢,就会报错:


用const声明后,张师傅、王师傅就只认得你家的地址了,不能再告诉他其他家的地址。

const:总结:1.必须给初始值 2.不能重复声明同一个变量 3.声明之后值不允许更改 4.没有变量提升 5.具有块级作用域特点

3. 快速让浏览器兼容ES6的方法
为什么就有兼容性问题?
由于广大用户使用的浏览器版本在发布的时候也许早于ES6的定稿和发布,而到了今天,我们在编程中如果使用了ES6的新特性,浏览器若没有更新版本,或者新版本中没有对ES6的特性进行兼容,那么浏览器肯定无法识别我们的ES6代码,好比浏览器根本看不懂我写的let和const是什么东西?只能报错了。这就是浏览器对ES6的兼容性问题。
如何解决兼容性问题?
针对ES6的兼容性问题,很多团队为此开发出了多种语法解析转换工具,把我们写的ES6语法转换成ES5,相当于在ES6和浏览器之间做了一个翻译官。比较通用的工具方案有babel,jsx,traceur,es6-shim等。此外,浏览器自身也加快速度兼容ES6的新特性,其中对ES6新特性最友好的是Chrome和Firefox浏览器。
即使浏览器对ES6新特性开始渐渐支持,但是这还需要很长一段时间,我们不能百分百依赖浏览器本身对ES6的支持度来开发。
虽然出现了各种转换工具,但是到目前为止,还没有一款工具能百分百将ES6的新特性完美地转换成ES5,因为在ES6新增的内容中,存在一些无法在ES5中找到与之匹配的语法,所以不建议在生产环境中使用支持度较低的新特性,后续的教程章节中介绍的新特性前端君也会特意提醒它的兼容性。 但是,这并不影响我们学习ES6的热情,因为ES6是未来的标准,浏览器支持只是迟早的事。
本节介绍其中一个转换工具的安装和使用情况,安装使用以简单为主,主要是让新手和刚接触的同学对转换工具有感性的认知。再次表明,即使使用了转换工具,我们还是不建议在生产环境大量地使用ES6的特性。
使用转换工具Babel

步骤一:制作ES6文件
新建一个html文件,取名为:ES6.html,加上含有ES6新特性的代码,比如:


步骤二:测试const兼容性
我们在chrome浏览器(版本不能太低)运行ES6.html,会正常运行,弹出“张三”。


接下来我们在IE9中看下结果:


IE 9浏览器会提示我们第9行出现一个语法错误,相当于告诉我们它看不懂const是什么鬼,但是学过ES6入门系列第三节的我们都知道const是ES6的新增关键字,用于声明一个常量。这个时候我们知道const在IE9浏览器出现了兼容性问题了。下面我们开始用Babel来兼容它。我们可以使用npm来安装babel,npm是随同Nodejs一起安装的包管理工具,新版的nodejs已经继承了npm,我们只要安装nodejs即可。

步骤三:安装node
node官网(下载安装包.msi):https://nodejs.org/


我们点击v10.15.3LTS进行下载,下载后找到node-v10.15.3-x64.msi双击运行,点击next(下一步)安装即可。期间你可以自定义选择安装的位置,默认是C:\ProgramFiles\。最后一步点击 Finish(完成)按钮退出安装向导。

步骤四:检测node是否安装成功
安装结束后,我们检测是否安装成功:点击 “开始”-> “运行”-> 输入“cmd”-> 进入命令提示符窗口,输入“node --version”来检测当前node的版本。


出现:v10.15.X就表示安装成功,因为我下载的就是v10.15.0LTS。

步骤五:用npm安装babel
node安装好了,也就是它集成的npm包管理工具也安装好了,接下来,我们利用npm来安装我们最想要的babel。
同样我们启动命令提示符窗口并且输入:npm install babel-core@5,然后回车,这里要稍等片刻:


看到上面的界面就是表示你安装babel成功,你会在电脑盘中找到这样的目录:C:\Users\Administrator\node_modules\babel-core,打开后你会看到:


在这个目录里面我们找到babel的浏览器版本browser.js(未压缩版)和browser.min.js(压缩版)。
步骤六:使用bable
然后我们将这个文件使用在我们的ES6.html中。



我们把browser.min.js引入(文件位置的路径要确保正确)。并且设置第二个script标签的type为”text/babel”。
步骤七:让const运行在IE9上
我们在ie9上运行下:


这个时候IE9能正常运行我们的ES6新特性了,也就是babel转换起作用了,讲const转换成IE9能执行的代码了。


4. 解构赋值
4.1 什么是解构赋值
ES6允许按照一定模式,从数组和对象中提取值,对变量进行赋值,这被称为解构(Destructuring)。
关于给变量赋值,传统的变量赋值是这样的:


将数组的元素值1,2,3分别赋值给变量a,b,c,结果也是如我们所愿,赋值成功,这是一种传统的赋值方式。
变量的解构赋值:


注意到了吗?赋值的代码大大减少了,不需要分别把变量a,b,c分别声明定义和赋值,只需要将变量a,b,c作为一个数组的元素,然后将数组[1,2,3]赋值给数组[a,b,c]即可,变量a,b,c即可分别得到对应的值。

4.2 数组的解构赋值
1. 解构赋值可以嵌套


如我们的预料,数组中即使再嵌套另一个数组,解构赋值也能为我们的变量准确的赋值,c1和c2的值分别为3.1 , 3.2,也就是赋值成功。
2. 不完全解构


当左边的模式(你可以理解为格式)与右边不完全一样的时候,那么赋值过程中,只会给模式匹配成功的部分的变量赋值,例如:变量c没有在右边找到匹配的模式,所以无法进行赋值,但这并不影响变量a和变量b的赋值,因为它们在右边找到与之匹配的模式,这种叫做不完全解构。
3. 赋值不成功,变量的值为undefined


还是接着上面的不完全解构例子讲解,变量a和变量b为不完全解构,那么变量c解构不成功会怎么样呢?记住,解构不成功,变量的值就等于undefined。相当于只声明了变量c,但是没赋值。
4. 允许设定默认值


例子中变量c已经指定默认值为3,即使右侧没有与之对应的值赋给它也没关系,它都可以成功赋值为3,如果你想覆盖默认值3,只需赋一个有效的值即可。如下:


这个时候默认值3会被新的值4覆盖,c的值为4;注意:当新的值为undefined的时候,是不会覆盖默认值的。

4.3 对象的解构赋值
对象的解构赋值跟数组的解构赋值很类似,我们来看一段小代码:


这段例子的代码是不是跟数组的解构赋值很相似,只不过是数组换成了对象。但是两者有一个不同的地方,我们对上面的代码稍做修改:


我把右侧的对象属性b和属性c的位置进行了调换,但这并不会影响赋值的结果,变量b和变量c的值不会改变,依然是b为2,c为3。这就告诉我们对象的解构赋值不会受到属性的排列次序影响(数组则会受影响),它是跟属性名关联起来的,变量名要和属性名一致,才会成功赋值。
如果变量找不到与其名字相同的属性,就会赋值不成功,如下面的例子:


变量a在右侧找不到与之名字匹配的属性a,所以变量a赋值不成功,a的值为undefined。
但也不是完全没有办法补救的,如果你想给一个变量名与属性名不一样的变量解构赋值,可以这样写:


这样变量a同样可以赋值成功,a的值最终为2。

对象的解构赋值的用法与数组的解构赋值也很类似:
1. 对象解构赋值也可以嵌套


2. 可以指定默认值


总结: 1.等号左边是变量名,等号右边的属性值不能是变量名,属性不能是值
2.如果有嵌套格式,那么只需要对照左右两侧的值即可
3.等号左边赋初始值,如果想要拿到初始值,只要右侧的变量不匹配即可

4.4 字符串的解构赋值
除了对象和数组可以解构赋值外,字符串也可以这么玩,看看下面的例子:


这是因为在解构赋值的过程中,字符串被转换成了一个类似数组的对象。变量a,b,c,d,e,f都分别赋上了对应的值。

4.5 解构赋值的用途
1. 交换变量的值
传统做法最常用的是引入第三个变量来临时存放,如下:


但是有了解构赋值,想交换两个变量的值就简单多了。看下面的代码:


简单的一句代码即可成功交换x,y的值。

2. 提取函数返回的多个值
函数只能返回一个值,我们可以将多个值装在一个数组或者对象中,再用解构赋值快速提取其中的值。


将demo函数的运行结果通过结构赋值给变量name和age,实现快速的提取对应的值。

3. 定义函数参数


通过这种写法, 很方便就能提取JSON对象中想要的参数,例如案例中,我们只需要获取实参中的:a,b,c,而不需要关其他的参数,比如:d或者其他更多的参数。

4. 函数参数的默认值
传统的参数默认值的实现方式是,先判断该参数是否为undefined,如果是代表没传,需要手动给它赋一个值,如:


但是有了解构赋值,一切都变得简单很多!看下面的代码:


上面的代码给我们展示了通过解构赋值设定函数参数的默认值,简洁地代码即可实现。函数调用的时候没有传入对应的name参数,此时name就会使用默认值:“张三”,是不是很简洁很方便。
以上介绍了解构赋值的4个用途,你是不是也感觉到了它给我们带来的方便,它使我们的代码量大大的减少,并且语法十分清晰,增加了代码的可读性和表现力。

let 总结:1.let具有块级作用域 2.let 不会进行变量提升
注意:1.未声明使用会报错 2.不允许有重复的变量名 3.函数内不允许声明与形参相同的变量名

const:总结:1.必须给初始值 2.不能重复声明同一个变量 3.声明之后值不允许更改 4.没有变量提升 5.具有块级作用域特点

总结: 1.等号左边是变量名,等号右边的属性值不能是变量名,属性不能是值
2.如果有嵌套格式,那么只需要对照左右两侧的值即可
3.等号左边赋初始值,如果想要拿到初始值,只要右侧的变量不匹配即可

posted on 2020-08-04 22:26  SKT-otto  阅读(67)  评论(0编辑  收藏  举报