文章目录
1 .ECMAScript 6 简介
ECMAScript 和 JavaScript 的关系
- ECMAScript 和 JavaScript 的关系是,前者是后者的规格,后者是前者的一种实现
ES6 与 ECMAScript 2015 的关系
- ES6 这个词的原意,就是指 JavaScript 语言的下一个版本
- ES6 既是一个历史名词,也是一个泛指,含义是 5.1 版以后的 JavaScript 的下一代标准,涵盖了 ES2015、ES2016、ES2017 8 9 等等
Babel 转码器
- 可以将 ES6 代码转为 ES5 代码,从而在现有环境执行。这意味着,你可以用 ES6 的方式编写程序,又不用担心现有环境是否支持
2. let 和 const 命令 和var的区别
不存在变量提升
let不允许在相同作用域内,重复声明同一个变量
顶层对象的属性 § ⇧
- 顶层对象,在浏览器环境指的是window对象,
- 在 Node 指的是global对象。ES5 之中,
- 顶层对象的属性与全局变量是等价的。
块级作用域
- 第一种场景,内层变量可能会覆盖外层变量。
- 第二种场景,用来计数的循环变量泄露为全局变量。
暂时性死区 TDZ
CONST 声明
- const声明一个只读的常量。一旦声明,常量的值就不能改变。
- const一旦声明变量,就必须立即初始化,不能留到以后赋值。
- 变量指向的那个内存地址不得改动
3. ES6 声明变量的六种方法
- ES5 只有两种声明变量的方法:var命令和function命令。
- ES6 除了添加let和const命令,
- 另外两种声明变量的方法:import命令和class命令。
4. 变量的解构赋值
数组的解构赋值
- 完全解构
- 不完全解构
- 赋默认值
对象的解构赋值
- 键名解构
- 起别名
字符串的解构赋值
- 用途
-交换变量的值 - 函数参数的定义
- 提取 JSON 数据
- 函数参数的默认值
- 遍历 Map 结构( Iterator 接口的对象)
5. 数组的方法
- 扩展运算符
- Array.from()
- Array.of()
- 数组实例的 copyWithin()
- 数组实例的 find() 和 findIndex()
- 数组实例的 fill()
- 数组实例的 entries(),keys() 和 values()
- 数组实例的 includes()
- 数组实例的 flat(),flatMap()
- 数组的空位
6. 对象扩展
- Object.is()
- Object.assign()
- Object.keys(),Object.values(),Object.entries()
- Object.fromEntries()
7. 字符串的方法
- String.fromCodePoint()
- String.raw()
- 实例方法:codePointAt()
- 实例方法:normalize()
- 实例方法:includes(), startsWith(), endsWith()
- 实例方法:repeat()
- 实例方法:padStart(),padEnd()
- 实例方法:trimStart(),trimEnd()
- 实例方法:matchAll()
8. Set和Map
-
set.size:类似于length 长度
-
add(value):添加某个值,返回 Set 结构本身
-
delete(value):删除某个值,返回一个布尔值,表示删除是否成功。
-
has(value):返回一个布尔值,表示该值是否为Set的成员。
-
clear():清除所有成员,没有返回值。
-
map.set(key,val)
-
map.get(key)
-
map.has()
9. Promise
基本API
- Promise.prototype.then()
- Promise.prototype.catch()
- Promise.prototype.finally()
- Promise.all()
- Promise.race()
- 应用
- Promise.try()
在 JavaScript 中,所有代码都是单线程的,也就是同步执行的。而 Promise 就
Promise 是异步编程的一种解决方案,其实是一个构造函数,自己身上有all、reject、resolve这几个方法,原型上有then、catch等方法。
概念:
Promise 对象用于表示一个异步操作的最终完成(或失败),及其结果值。为异步编程提供了一种解决方案。
特点:
- 对象的状态不受外界影响。
Promise对象代表一个异步操作,有三种状态:pending(进行中)、fulfilled(已成功)和rejected(已失败)。
- 一旦状态改变,就不会再变,任何时候都可以得到这个结果。
Promise对象的状态,只有两种可能:从 pending 变为 fulfilled 和从 pending 变为 rejected。
使用:
Promise 对象是由 关键字 new 构造函数来创建的。
let p = new Promise((resolve, reject)=> {
//做一些异步操作
setTimeout(()=> {
console.log('执行完成');
resolve('可以任何数据例如接口返回数据');
}, 1000);
});
//执行结果:执行完成
//执行过程:执行一个异步操作,也就是setTimeout,1秒后,输出“执行完成”,并且调用resolve方法。
注意!我只是new了一个对象,并没有调用它,就已经执行了。所以用Promise的时候一般是包在一个函数中,在需要的时候去运行这个函数。
<button onclick="promiseClick()">开始异步</button>
<script>
const promiseClick = () => {
return new Promise((resolve, reject) => {
//做一些异步操作
setTimeout(() => {
console.log('执行完成');
resolve('可以任何数据例如接口返回数据');
}, 1000);
});
}
</script>
//刷新页面的是没有执行的,点击后控制台打出。
//执行:执行完成
解决俩个问题
1、为什么要放在函数里面
2、resolve是个什么
我们包装好的函数后,会 return 出 Promise 对象,执行这个函数我们得到了一个Promise对象。接下来就可以用Promise对象上的then、catch方法了,这就是Promise的强大之处了。
promiseClick().then((data)=>{
console.log(data);
//后面可以用传过来的数据做些其他操作
//......
})
//执行:执行完成
//resolve('xx');中的内容或数据
首先方法被调用执行了promise,最后执行了promise的then方法,then方法是一个函数接受一个参数是resolve返回的数据;就输出了 resolve 中内容。
then里面的函数就是回调函数,能够在promiseClick这个函数异步任务执行完成后被执行。这就是Promise的作用。简单来讲,就是能把原来的回调写法分离出来,在异步操作执行完后,用链式调用的方式执行回调函数。
那么,如果有多层回调该怎么办?
而Promise的优势在于可以在then方法中继续写Promise对象并返回,然后继续调用then来进行回调操作。
所以:Promise能够简化层层回调的写法 Promise的精髓是“状态”,用维护状态、传递状态的方式来使得回调函数能够及时调用,优点简单、灵活。
//函数返回promise对象
let a = ()=>{
return new Promise((r, j) => {
setTimeout(() => {
r("a数据");
}, 2000)
})
}
//函数返回promise对象
let b = ()=>{
return new Promise((r, j) => {
setTimeout(() => {
//使用数据
// console.log("bbb" + data);
r("b数据");
}, 1000)
})
}
//有了以上执行函数,用一个Promise对象来执行它们
let sum = ()=>{
return new Promise((r, j) => {
setTimeout(() => {
r("第一");
}, 500)
})
}
//执行
sum().then((sum)=>{
console.log(sum);
return a();
})
.then((aa)=>{
console.log(aa);
return b();
}).then((bb)=>{
console.log(bb);
})
.catch((err) => {
console.log(err); // err 输出 j("失败信息")
})
//执行:第一
// a数据
// b数据
这样按顺序,每个异步回调成功后的内容,在sum中传给resolve的数据,能在接下来的then方法中拿到依次类推。
reject的用法
以上是resolve用法进行了解释,resolve是对promise成功时候的回调,它把promise的状态修改为
fullfiled(已成功)。
在 then中可以传两个参数。
then方法可以接受两个参数分别是函数,第一个对应resolve的回调,第二个对应reject的回调。所以我们能够分别拿到回调函数中成功的数据和失败的原因,并不会卡死 Js 代码运行。
//执行
sum().then((sum)=>{
console.log(sum);
return a();
},(err)=>{
console.log(err); // j("失败内容")
})
.then...
catch的用法
reject 就是失败的时候的回调,他把promise的状态修改为 rejected,这样我们在 catch 中就能捕捉到,然后执行“失败”情况的回调。
//执行
.catch((err) => {
console.log(err);
})
all的用法
与then同级的另一个方法,该方法提供了并行执行异步的操作,在所有异步操作执行完且执行结果都是成功的时候才执行。
let a = ()=>{
return new Promise((r, j) => {
setTimeout(() => {
r("aaa数据");
}, 1000)
})
}
let b = ()=>{
return new Promise((r, j) => {
setTimeout(() => {
r("bbb数据");
//j("失败了")
}, 1000)
})
}
Promise.all([a(),b()])
.then((result) => {
console.log(result);
}).catch((err) => {
console.log(err);
});
使用 Promise.all 来执行,all接收一个数组参数,这组参数为需要执行异步操作的所有方法,里面的值最终都算返回Promise对象。
异步操作是并行执行的,等到它们都执行完后才会进到then里面。all会把所有异步操作的结果放进一个数组中传给then,然后再执行then方法的成功回调将结果接收。
应用场景:比如你需要提前准备好所有数据才渲染页面时就可以使用all,执行多个异步操作将所有的数据处理好,再渲染。
race的用法
all是所有的异步操作都执行完再执行then方法,那么race方法就是相反的,谁先执行完成就先执行回调。先执行完的不管是进行了race的成功回调还是失败回调,其余的将不会再进入race的任何回调。
(赛跑规则)
let a = () => {
return new Promise((r, j) => {
setTimeout(r,300,'r-300');
})
}
let b = () => {
return new Promise((r, j) => {
setTimeout(r,100,'r-100');
})
}
Promise.race([a(), b()])
.then((result) => {
console.log(result);
}).catch((err) => {
console.log(err);
});
//执行:r-100
10. Generator + CO
Generator 函数是一个普通函数。
区别:
- function关键字与函数名之间有一个星号。(ES6 没有规定,function关键字与函数名之间的星号,写在哪个位置都能通过。)
- 函数体内部使用yield表达式,定义不同的内部状态(yield在英语里的意思就是“产出”)。
- 调用 Generator 函数后,该函数并不执行,返回的也不是函数运行结果,而是一个指向内部状态的指针对象,也就是遍历器对象(Iterator Object)。必须调用遍历器对象的 next() 方法,使得指针移向下一个状态
function * helloWorldGenerator() {
yield console.log('hello');
yield console.log('world');
return console.log('ending');
}
var hw = helloWorldGenerator();
— 控制台输入 hw.next();
hw.next();
index.html:156 hello
hw.next();
index.html:157 world
hw.next();
index.html:158 ending
必须调用遍历器对象的 next() 方法,使得指针移向下一个状态。每次调用next方法,内部指针就从上一次停下来的地方开始执行,直到遇到下一个yield表达式(或return语句)为止。
换言之,Generator 函数是分段执行的,yield表达式是暂停执行的标记,而next方法可以恢复执行。
上面代码定义了一个 Generator 函数helloWorldGenerator,它内部有两个yield表达式(hello和world),即该函数有三个状态:hello,world 和 return 语句(结束执行)。
yield 表达式
由于 Generator 函数返回的遍历器对象,只有调用next方法才会遍历下一个内部状态,所以其实提供了一种可以暂停执行的函数。yield表达式就是暂停标志。
next方法
(1)遇到yield表达式,就暂停执行后面的操作,并将紧跟在yield后面的那个表达式的值,作为返回的对象的value属性值。
(2)下一次调用next方法时,再继续往下执行,直到遇到下一个yield表达式。
(3)如果没有再遇到新的yield表达式,就一直运行到函数结束,直到return语句为止,并将return语句后面的表达式的值,作为返回的属性值。
(4)如果该函数没有return语句,则返回的对象的value属性值为undefined。
yield表达式后面的表达式,只有当调用next方法、内部指针指向该语句时才会执行,因此等于为 JavaScript 提供了手动的“惰性求值”(Lazy Evaluation)的语法功能。
用途:
ajax的异步处理,需要等待别的异步成功后再执行
function* main() {
...
var result = yield request("http://www.xxx.com?rows=10&f={firstName}");
console.log(result);
//do 别的ajax请求;
}
co 是什么
co是用来自动执行generator函数的工具。generator的好处是可以在定义函数时候就打上“断点”,调用函数时候可以在断点的地方暂停函数的执行。Generator带来的问题是如何控制什么时候进行下一步调用。co可以解决这个问题。
特点:
1、co 模块,它基于 ES6 的 generator 和 yield ,能用同步的形式编写异步代码的nodejs模块。
代码如下:
const co = require ('co');
function* main() {
执行代码。。。
});
co(main);
co 模块可以将异步解改成同步。co 函数接受一个 generator 函数作为参数,在函数内部自动执行 yield 。
co实现generator自动执行的条件
需要yield后面的数据类型为:
- promises
- thunks (functions)
- array (parallel execution)
- objects (parallel execution)
- generators (delegation)
- generator functions (delegation)
最后两种类型是官方建议避免使用的。
使用:
安装:
$ npm install co
index.js
function* helloWorldGenerator() {
var a = Promise.resolve(1);
var b = Promise.resolve(2);
var c = Promise.resolve(3);
var res = yield [a, b, c];
console.log(res);
}
co(helloWorldGenerator).catch(onerror);
// 执行: [1, 2, 3]
function onerror(err) {
console.error(err);
}