异步
回调函数在我们有异步请求时,经常被用到。但是由于回调地狱,不得不让我们去探寻更优雅的书写方式
Promise
promise有两个关键点,一个是状态status一个是值value
起初,当我们new 一个 Promise 对象时候,promise的状态是pending(挂起状态)
当执行到resolve和reject函数的情况下,才会触发状态的改变。
当然,一旦状态改变,我们就会发生值得传递
function test () {
return new Promise((resolve, reject) => {
setTimeout( () => {
resolve('hahah, this is promise') //状态更改为fullfilled
}, 3000)
})
}
test().then((res) => {
console.log('this is res', res)
return new Promise((resolve, reject) => {
setTimeout( () => {
resolve('this is the second')
}, 2000)
})
}).then (
(res) => {
console.log(res)
}
)
一旦resolve触发,status更改后,对应的值会传到.then中的函数中。
这时我们要注意then的参数有两个,一个是成功时调用的函数,一个是不成功时调用的函数。
但我们不为then传递正确的函数参数时,.then会返回一个空的promise
Promise.all
当我们异步并行接收多个请求时
const one = Promise...
const two = Promise...
const three = Promise...
Promise.all([one,two,three]).then()
Promise.race
竞态获得请求,看哪个请求回来的快
总结
总的看来promise到底比过去的回调函数好在了哪。首先,我们将一个个的异步操作都封装到一个promise对象中,这样我们再操作这些异步函数特别方便,就好比变量一样。
当一个个异步函数像变量以后,我们就可以顺序的处理请求,同时还可以并行或者竞态的处理请求,这是过去回调函数做做不到的。
最后,promise就好像给回调函数套了一层开关,而回调函数更改promise的状态
async...await
async...await语法糖对promise用法做出了改进
async function test () {
return 12
}
test.then((val)=>{console.log(item)})
通过关键字async可以让异步函数将返回值自动转化为promise对象
return 12 == return Promise.resolve(12)
当我们在异步函数中使用异步函数,会出现函数调用顺序问题。这时我们应该使用await关键字
反射
传统函数调用方式是根据对象操作函数,但是反射则是根据函数判断执行哪个对象
let price = 92.3
console.log(Reflect.apply(price>100?Math.floor:Math.ceil,null,[price])
可以看出反射机制实际上是一种动态的操作,我们事先知道要发生的动作,但是却不知道这个动作将要施加在哪个对象上,这一切都是一个动态变化的
ES5中许多object的操作都可以通过reflect实现,但是reflect的有object实现不了的功能,reflect更加规范化,而且也是为了的发展方向。归于reflect的api我会慢慢更新
Reflect.construct
for await of
目标是实现异步遍历
代理
可以理解为是对数据的一种映像或是一种投影,我们可以通过这个投影读写数据,但是并不会对原数据造成影响
let obj ={
price: 134,
name:'zhangsan'
}
let b = new Proxy(obj,{
get (target,key) {
if (target[key]>130){
return 666
}
else {
return target[key]
}
},
set (target,key,value) {
target[key]=value
}
})
console.log(b.price,b.name) //666 "zhangsan"
在proxy第二个参数中,我们为读添加的限制
由定义方式可见,这是一种数据结构,创建proxy对象我们需要向构造函数传入两个参数。分别为代理对象和代理操作
//对于复杂的操作函数,我们可以进行解耦
let validator = (target,key,value)=>{
target[key]=value
}
set: validator
可撤销代理
let b = Proxy.revocable(...)
console.log(b.proxy.price)
b.revoke() //撤销这个代理
生成器
生成器功能类似数组,它最大的特点是可控,也就是可以手动控制每一步的向下执行
function * test () {
for(let i = 0; i<10 ; i++ ) {
yield alert(i)
}
}
let one = test()
one.next()
one.next()
one.next()
每当我们next,函数就会自动向下走一步,也就是寻找下一个yield。但是注意yield的返回是undefined的
function * test () {
let one = yield [1,2,3]
console.log(one)
}
let b = test()
b.next(10)
b.next(20) //20
当next中带有参数时,会有赋值作用
迭代器
迭代器的功能十分强大,我们可以通过自定义函数的方式,对复杂的数据结构进行操作,以达到实现复杂结构可以遍历。
迭代器有2个原则:一个是要写symbol.iterator一个是要有return false and value
let authors = {
allAuthors: {
fiction: [
'Agatha Christie',
'J. K. Rowling',
'Dr. Seuss'
],
scienceFiction: [
'Neal Stephenson',
'Arthur Clarke',
'Isaac Asimov',
'Robert Heinlein'
],
fantasy: [
'J. R. R. Tolkien',
'J. K. Rowling',
'Terry Pratchett'
]
}
}
// 这种结构是不能直接遍历的
为了实现特定数据结构的遍历,我们需要定制函数
let authors = {
allAuthors: {
fiction: [
'Agatha Christie',
'J. K. Rowling',
'Dr. Seuss'
],
scienceFiction: [
'Neal Stephenson',
'Arthur Clarke',
'Isaac Asimov',
'Robert Heinlein'
],
fantasy: [
'J. R. R. Tolkien',
'J. K. Rowling',
'Terry Pratchett'
]
}
}
authors[Symbol.iterator] = function () {
let author = this.allAuthors
let key = Reflect.ownKeys(author)
let val = []
return {
next(){
if(!val.length){
if(key.length){
val = author[key[0]]
key.shift()
}
}
return {
done: !val.length,
value: val.shift()
}
}
}
}
let q=[]
for(let v of authors) {
q.push(v)
}
console.log(q)
但是这种定义的迭代器可以复用吗
import导入
import导入机制为模块化提供了极大的遍历,文件可以灵活的根据需要导入模块
import {one ,two as what} from './1.js'
在1.js中
export { one, two}
import one(可以是任意名) from './2.js'
在2.js中
export default one
export导出可以是多次导出,但是export default只能出现一次
模块文件
export {...}
export default class People {}
导入文件
import * as mod from '..文件路径'
export 中的函数可以通过mod.函数调用
但是,export default会改写类名People,所以People这个类如果想
被调用,我们要用mod.default
ES beyond
flat/flatMap
对于多维数组,注意一定是纯数组的类型下,我们可以用flat对数组降维。注意,它的返回值是一个新数组
const one = [1,[2,3],[4,[5]]]
console.log(one.flat(3)) //1,2,3,4,5
flat中的参数为深度参数
flatMap则是map和flat的结合,在遍历所有元素后,扁平化数组
Object.fromEntries\Object.entries
通过Object.entires可以将对象转化为数组,注意对象中不能嵌套对象
通过Object.fromEntries可以将数组转化为对象,但是数组深度只能为1
去除空格
Object数据的描述符
通过这个属性,我们可以直观的看到每个对象的具体信息
清单
symbol