ES6 总结

2020-03-11

ES6 官方文档

一. let const var 区别

var: 声明一个变量,可同时将其初始化为一个值。
let: 声明一个块级本地变量,可同时将其初始化为一个值。 let的特点是不会变量提升。
const: 声明一个只读命名常量。

实例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
for(var i = 0; i < 5; i++) {
setTimeout(() => {
console.log(i) //5, 5, 5, 5, 5
}, 0)
}
console.log(i) //5 i跳出循环体污染外部函数

//将var改成let之后
for(let i = 0; i < 5; i++) {
setTimeout(() => {
console.log(i) // 0,1,2,3,4
}, 0)
}
console.log(i)//i is not defined i无法污染外部函数
1
2
3
4
5
6
7
var a = [];
for (var i = 0; i < 10; i++) {
a[i] = function () {
console.log(i);
};
}
a[6](); // 10
1
2
3
4
5
6
7
var a = [];
for (let i = 0; i < 10; i++) {
a[i] = function () {
console.log(i);
};
}
a[6](); // 6

ES6 声明变量的六种方法
ES5 只有两种声明变量的方法:var命令和function命令。
ES6 除了添加letconst命令,后面章节还会提到,另外两种声明变量的方法:import命令和class命令。所以,ES6 一共有 6 种声明变量的方法。

参考链接


二. promise

Promise 是异步编程的一种解决方案。
Promise 对象代表一个异步操作,有三种状态:pending(进行中)、fulfilled(已成功)和rejected(已失败)。
Promise 对象的状态改变,只有两种可能:从 pending 变为 fulfilled 和从 pending 变为
rejected。只要这两种情况发生,状态就凝固了,不会再变了,会一直保持这个结果,这时就称为 resolved(已定型)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
const someAsyncThing = function(flag) {
return new Promise(function(resolve, reject) {
if(flag){
resolve('ok');
}else{
reject('error');
}
});
};

someAsyncThing(true).then((data)=> {
console.log('data:',data); // 输出 'ok'
}).catch((error)=>{
console.log('error:', error); // 不执行
})

someAsyncThing(false).then((data)=> {
console.log('data:',data); // 不执行
}).catch((error)=>{
console.log('error:', error); // 输出 'error'
})
1
2
3
4
5
// 发起异步请求
fetch('/api/todos')
.then(res => res.json())
.then(data => ({ data }))
.catch(err => ({ err }));

重点:考察 JavaScript 的运行机制

解析: JS的解析过程分为两个阶段:预编译期(预处理)与执行期。
预编译期JS会对本代码块中的所有声明的变量和函数进行处理(类似与C语言的编译),但需要注意的是此时处理函数的只是声明式函数,而且变量也只是进行了声明但未进行初始化以及赋值。

换种说法:

  1. 开始执行
  2. 逐步执行代码
  3. 代码同步操作
    如果有异步操作,插入到异步队列。异步队列中,先执行微任务,再执行宏任务。
  4. 执行完毕。
    检查3里面的异步队列。

微任务:promise
宏任务:script 标签对, setTimeout, setInterval

1
2
3
4
5
6
7
8
9
10
11
setTimeout(() =>{
console.log('set1');
})
new Promise((resolve,reject)=>{
console.log("p1");
resolve();//同步
}).then(()=>{
console.log('then1'); //异步
})
console.log(1);
//执行顺序: p1, 1, then1, set1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
setTimeout(() =>{
console.log('set1');
new Promise((resolve,reject)=>{
console.log('p2');
resolve();
}).then(()=>{
console.log('then2')
})
})
new Promise((resolve,reject)=>{
console.log("p1");
resolve();
}).then(()=>{
console.log('then1');
setTimeout(() => {
console.log('set2');
});
})
console.log(1);
//执行顺序: p1, 1, then1, set1, p2, then2, set2

参考链接

三. 函数

  1. ES6 允许为函数的参数设置默认值,即直接写在参数定义的后面。

    ES6 的写法还有两个好处:
    首先,阅读代码的人,可以立刻意识到哪些参数是可以省略的,不用查看函数体或文档;
    其次,有利于将来的代码优化,即使未来的版本在对外接口中,彻底拿掉这个参数,也不会导致以前的代码无法运行。

    1
    2
    3
    4
    5
    6
    7
    function log(x, y = 'World') {
    console.log(x, y);
    }
    //y 可传,可不传
    log('Hello') // Hello World
    log('Hello', 'China') // Hello China
    log('Hello', '') // Hello
  1. 箭头函数(=>)this 指向
    普通函数:

    1、函数作为全局函数被调用时,this指向全局对象
    2、函数作为对象中的方法被调用时,this指向该对象
    3、函数作为构造函数的时候,this指向构造函数new出来的新对象
    4、还可以通过call,apply,bind改变this的指向

    箭头函数:

    1、箭头函数没有this,函数内部的this来自于父级最近的非箭头函数,并且不能改变this的指向。 
    this属于词法作用域,直接由上下文确定
    2、箭头函数没有super
    3、箭头函数没有arguments
    4、箭头函数没有new.target绑定。
    5、不能使用new
    6、没有原型
    7、不支持重复的命名参数。

在箭头函数中,this属于词法作用域,直接由上下文确定,对于普通函数中指向不定的this,箭头函数中处理this无疑更加简单

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//ES5普通函数
function Man(){
this.age=22;
return function(){
this.age+1;
}
}
var cala=new Man();
console.log(cala())//undefined

//ES6箭头函数
function Man(){
this.age=22;
return () => this.age+1;
}
var cala=new Man();
console.log(cala())//23

箭头函数中没有arguments(我们可以用rest参数替代),也没有原型,也不能使用new 关键字

1
2
3
4
5
6
7
8
9
10
11
12
13
14
//没有arguments
var foo=(a,b)=>{return arguments[0]*arguments[1]}
console.log(foo(3,5))
//arguments is not defined

//没有原型
var Obj = () => {};
console.log(Obj.prototype);
// undefined

//不能使用new 关键字
var Obj = () => {"hello world"};
var o = new Obj();
// TypeError: Obj is not a constructor

四. 字符串

  1. 模板字符串 (用反引号来表示)
    可以用${}来表示模板占位符,可以将你已经定义好的变量传进括弧中
    实例

    1
    2
    3
    var name="cala";
    var age=22;
    console.log(`hello,I'am ${name},my age is ${age}`)
  2. includes(str, index):如果在字符串中检测到指定文本,返回true,否则false。
    startsWith(str, index):如果在字符串起始部分检测到指定文本,返回true,否则返回false。
    endsWith(str, index):如果在字符串的结束部分检测到指定文本,返回true,否则返回false。

    第二个参数,表示开始搜索的位置。可不写。
    实例

    1
    2
    3
    4
    let s = 'Hello world!';
    s.startsWith('world', 6) // true
    s.endsWith('Hello', 5) // true
    s.includes('Hello', 6) // false

五. Map和Set (ES6标准新增的数据类型)

Map和Set都叫做集合

Map: Map结构是键值对集合
集合常被用来获取已存的信息
Set: Set结构是类似于数组结构,
常被用来检查对象中是否存在某个键名

Map: key:value

1
2
3
4
5
6
7
var map = new Map(); // 空Map
map.set('Adam', 67); // 添加新的key-value
map.set('Bob', 59);
map.has('Adam'); // 是否存在key 'Adam': true
map.get('Adam'); // 67
map.delete('Adam'); // 删除key 'Adam'
map.get('Adam'); // undefined

Set: key不能重复,Set没有索引
要创建一个Set,需要提供一个Array作为输入,或者直接创建一个空Set:

1
2
3
4
5
6
7
8
9
10
11
12
let set = new Set()
// Set转化为数组
let arr = Array.from(set)
let arr = [...set]
// 实例属性(继承自Set)
set.constructor === Set

// 操作方法
set.add(1) // 添加一个值
set.delete(1) //删除一个值
set.has(1) //判断是否有这个值(Array中的indexOf)
set.clear() //清除所有值

Map 实例:查询
假设要根据同学的名字查找对应的成绩,如果用Array实现,需要两个Array:

1
2
var names = ['Michael', 'Bob', 'Tracy'];
var scores = [95, 75, 85];

给定一个名字,要查找对应的成绩,就先要在names中找到对应的位置,再从scores取出对应的成绩,Array越长,耗时越长。
如果用Map实现,只需要一个“名字”-“成绩”的对照表,直接根据名字查找成绩,无论这个表有多大,查找速度都不会变慢。用JavaScript写一个Map如下

1
2
var m = new Map([['Michael', 95], ['Bob', 75], ['Tracy', 85]]);
m.get('Michael'); // 95

Set 实例:去重

1
2
3
let arr1 = [1,2,3,4,5];
let arr2 = [4,5,6,7,8];
new Set([...arr1,...arr2]) //{1,2,3,4,5,6,7,8}

六. async 函数

await
ES2017 标准引入了 async 函数,使得异步操作变得更加方便。

async 函数返回的 Promise 对象,必须等到内部所有 await 命令后面的 Promise 对象执行完,才会发生状态改变,除非遇到 return 语句或者抛出错误。
也就是说,只有 async 函数内部的异步操作执行完,才会执行 then 方法指定的回调函数。

1
2
3
4
5
6
async function getTitle(url) {
let response = await fetch(url);
let html = await response.text();
return html.match(/<title>([\s\S]+)<\/title>/i)[1];
}
getTitle('https://tc39.github.io/ecma262/').then(console.log('完成'))

上面代码中,函数 getTitle 内部有三个操作:抓取网页、取出文本、匹配页面标题。只有这三个操作全部完成,才会执行 then 方法里面的 console.log。