1.ECMAcript6的简介
ECMAScript6是js语言的一代标准,于2015年6月发布,本节将介绍ES6的概念及转码器babel的使用。
1.1ECMAScript6的概念
ECMAScript和JavaScript的关系是:前者是后者的规格,后者是前者的一种实现。
ES6和ECMAScript 2015的关系:ES6既是一个历史名词,也是一个泛指,含义是5.1版以后的JS的下一代标准,涵盖了ES2015,ES2016,ES2017等,而ES2015则是正式名称,特指该年发布的正式版本的语言标准。本章中提到的ES6,一般是指ES2015标准。
1.2 ES6转码器babel的使用
babel是一个广泛使用的ES6转码器,可以将ES6代码转换为ES5代码,从而在老版本的浏览器中执行。配置步骤在~~~。
2.let和const命令
2.1 let命令
用来声明变量。它的用法类似于var,但其声明的变量只在let命令所在的代码块内有效。
语法:let 变量名;
- let命令作用域只局限于当前代码块
- 使用let命令声明的变量作用域不会被提前
- 在相同的作用域下不能声明相同的变量
2.2 const命令
const命令用于声明一个只读常量。一旦声明,常量的值就不能改变。
语法:const 变量名;
const命令一但声明常量,就必须立即初始化,不能留到以后赋值。否则就会报错。
const的作用域于let相同,只在声明所在的块级作用域内有效。
const命令声明的常量也不支持提升,和let命令一样只能在声明之后使用。
同样const声明的常量,也与let一样不可以重复声明。
实际上,const命令保证的并不是常量的值不得改动,而是常量指向的内存地址不得改动。对于简单类型的数据(数值,字符串,布尔值),值就保存在常量指向的内存地址,因此等同于常量。但对于引用数据类型(如对象),常量指向的内存地址保存的只是一个对象地址,const只能保证这个对象地址是不能改变的,至于对象本身的属性是不是可变的,就完全不受控制了。
3.解析赋值
解构赋值是对赋值运算符的扩展。ES6允许按照一定模式从数组和对象中提取值,再对变量赋值,这被称为解构(Destructuring)。在代码编写上,解构赋值的写法更加简洁易懂,语言更加清晰明了。
3.1 数组解构赋值
3.1.1 基本使用
javascript">let [a,b,c]=[1,2,3];
console.log(a,b,c);//1,2,3
上面的代码表示可以从数组中提取值,按照对应位置对变量赋值,本质上,这种写法属于“模式匹配”,只要等号两边的模式相同,左边的变量就会被赋予对应的值。数组解构除基本用法外,还支持以下解构赋值形式。
3.1.2 解构嵌套数组
数组中可以包含数组,这被称为数组嵌套。下面代码中,变量数组中又包含数组。在匹配过程中,会按照对应位置为变量赋值。即变量a赋值为1,变量b赋值为2,变量c赋值为3。
javascript">let [a,[[b],c]]=[1,[[2],3]];
console.log(a,b,c);//1,2,3
3.1.3 不完全解构
正常解构赋值过程中,但变量数组匹配至一部分赋值的数组时,仍然可以解构成功,这时会将第一个匹配到的值赋给变量,多余的值忽略不计。
下面代码1中,变量a和b接受时,仅匹配到数组值中的1和2,而3则没有匹配成功。代码2中,变量a的值为1;变量b匹配嵌套数组中的第一个值,即2;变量c的值为4。
如果左右两边的数组缺少变量或值,均可解构成功。如果解构不成功,变量的值就等于undefined,如下代码3中变量a的值为1,变量b的值为3。
javascript">//代码1
let [a,b]=[1,2,3];
console.log(a,b);//1,2
//代码2
let [a,[b],c]=[1,[2,3],4];
console.log(a,b,c);//1,2,4
//代码3
let [a,,b]=[1,2,3];
console.log(a,b);//1,3
3.1.4剩余运算符
在解构赋值中,当无法得知变量值个数时,可以使用剩余运算符(...)进行模式匹配。通常,剩余运算符放在变量数组的最后,如下代码所示。在匹配时,变量a匹配1,变量b采用剩余运算符,则数组值的2和3都保存在变量b下,返回的结果b是一个数组,输出b显示[2,3]。
javascript">let [a,...b]=[1,2,3];
console.log(a,b);//1,[2,3]
3.1.5 解构默认值
解构赋值允许指定默认值。在匹配过程中,如果没有匹配成功,则变量值便是提前设置好的默认值。如下代码中,变量y设置默认值为"b"。在解构时,没有匹配到新的值,则输出显示变量y的值便是“b”。
javascript">let [x,y="b"]=["a"];
console.log(x,y);//"a","b"
3.2 对象解构赋值
对象的解构与数组的解构有一个重要的不同,数组的元素是按照次序排列的,变量的取值由它的位置决定,而对象的属性没有次序,变量必须与属性同名,才能取到正确的值。
javascript">//对象解构赋值的基本用法
let {a,b}={b:"y",a:"x"};
console.log(a,b);//x,y
let {abc}={def:"ghj"};
console.log(abc);//undefined
/*a,b两个变量的次序,与等号右边两个同名属性的次序不一致,但是对取值完全没有影响。
变量abc则没有对应的同名属性,导致取不到值,最后等于undefined*/
//为了解决对象解构赋值中变量名与属性名不一致的问题,
let {foo:x,bar:y}={foo:"ES6",bar:"hello"};
console.log(x,y);//ES6,hello
/**foo与bar是匹配的模式,x和y才是变量。真正被赋值的是变量x和y,而不是模式foo与bar。
* 通过这种写法即可解决变量名和属性名不一致的问题,对象解构赋值和数组解构赋值相同,
* 除基础用法外,支持如嵌套,不完全解构等形式,二者使用方法一致。*/
//解构嵌套对象
let obj={p:["hello",{c:"woeld"}]};
let {p:[z,{c}]}=obj;
console.log(z,c);//hello,world
//不完全解构
let obje={a,b,...rest}={a:10,b:20,c:30,d:40};
console.log(a,b,rest);//10,20,{c:30,d:40}
//解构默认值
let {q=10,m=5}={q:3};
console.log(q,m);//3,5
let {a:aa=10,b:bb=5}={a:3};
console.log(aa,bb)//3,5
3.3 字符串解构赋值
字符串解构赋值是将字符串转换成一个类似数组的对象,
javascript">let [a,b,c,d,e]="hello";
console.log(a,b,c,d,e);//h,e,l,l,o
3.4 函数参数解构赋值
javascript">function add([x,y]){
console.log(x+y);//3
}
add([1,2]);
函数add()的参数表面上是一个数组,但是在传入参数值的那一刻,数组的参数就被解构成变量x和y。对于函数内部的代码来说,得到的参数就是x和y。
4.函数扩展
4.1 函数参数默认值
javascript">function foo(x,y){
y=y || "world";
console.log(x,y);
}
foo("hello");//hello world
foo("hello","");//hello world
foo()函数包含两个参数,分别为x和y,其中对参数y设置默认值,当y没有被赋值时,y的值。y的值默认为“World”。
以ES6的写法为函数参数设置默认值。
javascript">function foo(x,y="world"){
console.log(x,y);
}
foo("hello");//hello world
foo("Hello","");//Hello
函数参数默认值也有它的局限性,具体表现如下。
- 参数变量是默认声明的,不能用let或const命令再次声明。
- 使用参数默认值时,函数不能有同名参数。
- 参数默认值一定要放在参数最后。
4.2 rest参数与name属性
rest参数用于获取多余参数,name属性用于获取函数名称。
4.3 箭头函数
语法:(参数1,,,参数N)=> {函数声明}
和普通函数的区别:
- 不绑定this对象
- 不绑定arguments对象
5.内置对象的扩展
5.1 字符串的扩展
5.1.2 模板字符串
javascript">let name="Bob",time="today";
document.write(`Hello ${name},how are you ${time}?`);
使用反引号(``)代替普通字符串中的双引号和单引号,可当作普通字符串使用,也可用来定义多行字符串。同时,使用模板字符串还可以嵌入变量,嵌入字符串或调用函数,
5.1.3 新增的字符串操作方法
方法 | 描述 |
---|---|
includes(string):boolean | 表示是否找到了参数字符串 |
startsWith(string):boolean | 表示参加数字字符串是否在原字符串头部 |
endsWith(string):boolean | 表示参数字符串是否在原字符串尾部 |
repeat(number):string | 返回一个新字符串,表示将原字符串重复n次 |
padStart(number,string):string | 用于头部补全 |
padEnd(number,string):string | 用于尾部补全 |
trimStart():string | 消除字符串头部的空客 |
trimEnd():string | 消除尾部的空格 |
javascript">let str = "hello ECMAScript";
console.log(str.includes("h"));//true
console.log(str.startsWith("h"));//true
console.log(str.endsWith("t"))//true
console.log(str.repeat(3))//hello ECMAScripthello ECMAScripthello ECMAScript
console.log(str.padStart(18,"a"));//aahello ECMAScript
console.log(str.padEnd(18,"z"));//hello ECMAScriptzz
console.log(str.trimStart());//消除字符串头部的空格
console.log(str.trimEnd());//消除字符串尾部的空格
5.2 数组的扩展
5.2.1 扩展运算符
扩展运算符使用三个点(...)表示,可以将一个数组转换为用逗号分隔的序列。
语法:...数组
5.2.2 Array.from()方法
from()方法用于将数组对象或可遍历对象转换成一个真正的数组。其中,类数组对象必须有length属性。如果没有length属性,则转换出来的是空数组。
语法:let list=Array.from(类数组);
5.2.3 数组遍历方法
方法 | 描述 |
---|---|
keys():iterator | 对键名的遍历 |
values():iterator | 对键值的遍历 |
entries():iterator | 对键值对的遍历 |
javascript">for(let [i,v] of ["张三","李四"].entries()){
console.log(i,v);
}
5.3 对象的扩展
5.3.1 属性的简洁表示法
javascript">let name="小明";
let birth="2023/5/19";
const Person={
name,
birth,
getInfo(){
console.log(`我的名字是:${this.name},我出生时间是:${this.birth}`);
}
}
Person.getInfo();//我的名字是:小明,我出生时间是:2023/5/19
5.3.2 对象新增方法
1.Object.is()方法
javascript">console.log(Object.is(NaN,NaN));//true
console.log(Object.is({},{}));//false
console.log(Object.is(+0,-0));//false
2.Object.assign()方法
语法:Object.assign(target,source_1,...);
该方法第一个参数是目标对象,后面的参数是源对象,可以包含多个源对象,也可以定义一个新对象接收目标对象。
5.3.3 对象遍历方法
方法 | 描述 |
---|---|
keys():iterator | 放回参数对象自身的所有可遍历属性的键名 |
values():iterator | 返回参数对象自身的所有可遍历属性的键值 |
entries():iterator | 返回参数对象自身的所有可遍历属性的键值对数组 |
6.Set和Map对象
6.1 Set对象
Set对象的数据结构类似于数组,但成员的值都是唯一的,没有重复的值。
分类 | 名称 | 描述 |
---|---|---|
属性 | size | Set实例的成员总数 |
操作方法 | add(value) | 添加某个值,返回Set结构本身 |
delete(value) | 删除某个值,返回一个布尔值,表示是否删除成功 | |
has(value) | 返回一个布尔值,表示该值是否为Set的成员 | |
clear() | 清除所有成员,没有返回值 | |
遍历方法 | keys() | 返回键名的遍历器 |
values() | 返回键值的遍历器 | |
entries() | 返回键值对的遍历器 | |
forEach() | 使用回调函数遍历每个成员 |
6.2 Map对象
js的对象(Object)本质上是键值对的集合(Hash结构),但是传统上只能使用字符串作为键,这给它的使用带来了很大的限制。为了解决这个问题,ES6提供了Map对象。它也就是键值对的集合,但其“键”的范围不限于字符串,各种类型的值()都可以被当作键。
分类 | 名称 | 描述 |
---|---|---|
属性 | size | Map对象的成员总数 |
操作方法 | set(key,value) | 设置键名key对应的键值为value,返回整个Map结构 |
get(key) | 读取key对应的键值,如果找不到key,返回undefined | |
has(key) | 返回一个布尔值,表示某个键是否在当前Map对象中 | |
delete(key) | 删除某个键,返回true。如果删除失败,返回fales | |
clear() | 清除所有成员,没有返回值 | |
遍历方法 | keys() | 返回键名的遍历器 |
values() | 返回键值的遍历器 | |
entries() | 返回所有成员的遍历器 |
7.Module语法
JS一直没有模块()体系,因此无法将一个大程序拆分成互相依赖的小文件,再用简单的方式拼装起来,对JS开发大型的,复杂的项目形成了障碍。
ES6模块的设计思想是尽量静态化,使得编译时就能确定模块得依赖关系。
7.1 export和import命令
在使用ES6的模块化设计时最常遇到的问题是如何导入,导出属性和方法。在创建或者使用分离到js文件中的模块时,常用到export命令导出对应属性和方法,用import命令导入对应的属性和方法
7.1.1 export命令
javascript">//第一种方法
export var b1 = "Michael";
export let b2 = "Jackson";
export const b3 = 1958;
//第二种方法
var a1 = "Michael";
let a2 = "Jackson";
const a3 = 1958;
export{a1,a2,a3};
7.1.2 import命令
7.2 export default命令
本章总结
人们眼中的天才之所以卓越非凡,并非天资超人一等,而是付出了持续不断的努力。1万小时的锤炼是任何人从平凡变成世界超级大师的必要条件。
——格拉德威尔《一万小时定律》