监听对象
Object.defineProperty设计的初衷,不是为了去监听截止一个对象中所有的属性的
如果我们想监听更加丰富的操作,比如新增属性、删除属性,那么Object.defineProperty是无能为力的
const obj = {
name:'www',
age:19
}
// 监听对象属性的操作
// 1. 监听一个属性
let _name = obj.name
Object.defineProperty(obj,'name',{
set(newValue) {
console.log('监听:给name设置了新的值:', newValue);
_name = newValue
},
get() {
console.log('监听:获取name的值');
return _name
}
})
// 2. 监听所有属性
const keys = Object.keys(obj)
for (const key of keys) {
let value = obj[key]
Object.defineProperty(obj,key,{
set(newValue){
console.log(`监听:给${key}设置了新的值:`, newValue);
value = newValue
},
get(){
console.log(`监听:获取${key}的值`);
return value
}
})
}
console.log(obj.name); // www
obj.name = 'wqq'
console.log(obj.name); // wqq
Proxy基本使用
先创建一个代理对象,之后对该对象的所有操作都通过代理对象来完成,代理对象可以监听对原对象进行的哪些操作
const obj = {
name: 'www',
age: 19
}
// 1. 创建一个代理对象
const objProxy = new Proxy(obj,{
/*
target:目标对象(侦听的对象)
property:将被设置的属性key
value:新属性值
receiver:调用的代理对象
* */
set(target,key,value){
console.log(`监听:给${key}设置了新的值:`,value);
target[key] = value
},
/*
target:目标对象
property:被获取的属性key
receiver:调用的代理对象
*/
get(target,key){
console.log(`监听:获取${key}的值`);
return target[key]
}
})
// 2. 对obj的所有操作,应该去操作objProxy
console.log(objProxy.name);
objProxy.name = 'wqq'
console.log(objProxy.name);
objProxy.address = '成都' // 也可以监听
- 其他捕获器的监听方法(了解)
const obj = {
name: 'www',
age: 19
}
const objProxy = new Proxy(obj, {
deleteProperty(target, p) {
console.log(`监听:删除${p}的值`);
delete obj.name
},
has(target, p) {
console.log(`监听:in判断${p}属性`);
return p in target
}
})
delete objProxy.name
console.log('age' in objProxy);
- 监听函数对象(了解)
function foo(n1,n2) {
console.log(this, n1, n2);
}
const fooProxy = new Proxy(foo,{
apply(target, thisArg, argArray) {
console.log('执行apply操作');
target.apply(thisArg,argArray)
},
construct(target, argArray, newTarget) {
console.log('监听new操作',target, argArray, newTarget);
return new target(...argArray)
}
})
foo.apply('aaa',[12,314])
new fooProxy('aaa','bbb')
Reflect的常见方法
在使用proxy时,不直接处理对象,让操作都集中到Reflect对象上
Reflect.set有返回布尔值,可以判断本次操作是否成功
const obj = {
name: 'www',
age: 19
}
const objProxy = new Proxy(obj,{
set(target, key, value, newValue) {
const isSuccess = Reflect.set(target,key,newValue)
if(!isSuccess) {
throw new Error(`set ${key} failure` )
}
},
})
objProxy.name = 'wqq'
console.log(obj);
Promise
- es5之前处理异步操作的代码
我们需要自己来设计回调函数、回调函数的名称、回调函数的使用
function execCode(counter, sussesCallback, failCallback) {
// 异步任务
setTimeout(() => {
if (counter > 0) {
let total = 0
for (let i = 0; i < 100; i++) {
total += i
}
sussesCallback(total)
} else {
failCallback(`${counter} 值有问题`)
}
}, 1000)
}
execCode(100, (value) => {
console.log('成功了', value);
}, (err) => {
console.log('失败了', err);
})
- promise的使用
- 在通过new创建Promise对象时,我们需要传入一个回调函数
- 这个回调函数会被立即执行,并且给传入另外两个回调函数resolve、reject
- 当调用resolve回调函数时,会执行Promise对象的then方法传入的回调函数
- 当调用reject回调函数时,会执行Promise对象的catch方法传入的回调函数
Promise使用过程,我们可以将它划分成三个状态
状态一旦被确定,就不会改变,也不能再执行某一个回调函数来改变状态
const promise = new Promise((resolve, reject) => {
// 待定状态(pending)
console.log('Executor代码');
// 兑现状态(fulfilled)
resolve()
// 拒绝状态(rejected)
reject()
})
promise.then(value => console.log('成功了'))
.catch(err => console.log('失败了'))
// 这种写法也可以
promise.then(res => {
console.log('成功了', res);
},err => {
console.log('失败了', err);
})
function execCode(counter) {
return new Promise((resolve, reject) => {
setTimeout(() => {
if (counter > 0) {
let total = 0
for (let i = 0; i < 100; i++) {
total += i
}
// 成功时的回调
resolve(total)
} else {
// 失败时的回调
reject(`${counter}有问题`)
}
}, 1000)
})
}
const promise = execCode(100)
promise.then((value) => {
console.log('成功了', value);
})
promise.catch((err) => {
console.log('失败了', err);
})
execCode(222).then(value => console.log('成功了', value))
.catch(err => console.log('失败了', err))
then方法是返回一个新的promise,这个新的promise的决议是等到then方法传入的回调函数有返回值时,进行决议
链式中的then是在等待这个新的promise有决议后执行的
const promise = new Promise((resolve,reject) => {
resolve('成功')
})
promise.then(res => {
console.log('第一个then:',res); // 成功
return 'aaaa'
}).then(res => {
console.log('第二个then:',res); // aaa
}).then(res => {
console.log(res); // undefind
})
catch方法也会返回一个新的promise
const promise = new Promise((resolve,reject) => {
reject('失败')
})
promise.catch(err => {
return err
}).then(res => {
console.log('第一个失败',res); // 失败
return 'bbb'
}).then(res => {
console.log('第二个失败',res); // undefined
return 'ccc'
})
- resolve值的区别
const p = new Promise((resolve) =>{
setTimeout(() => {
console.log('p的resolve');
},1000)
})
const promise = new Promise((resolve, reject) => {
// 1. 普通值(数字、字符串、对象、数组...)
resolve(123)
// 2. resolve(promise):当前的promise的状态会由传入的promise决定
resolve(p) // 一秒后打印'p的resolve'
// 3.resolve(thenable对象)
resolve({
name:'www',
then(resolve) {
resolve('1232')
}
})
})
promise.then(res => console.log('成功了',res))
finally实例方法
表示无论Promise对象无论变成fulfilled还是rejected状态,最终都会被执行的代码
finally()是不接收参数的
const promise1 = new Promise((resolve, reject) => {
reject('失败')
})
promise1.then(res => console.log('成功了', res)) // 不会执行
.catch(err => console.log('失败了', err)) // 失败了 失败
.finally(() => console.log('执行代码')) // 执行代码
resolve、reject类方法
Promise.resolve()的用法相当于new Promise,并且执行resolve操作
Promise.reject()传入的参数无论是什么形态,都会直接作为reject状态的参数传递到catch的
const stu = []
const promise = Promise.resolve(stu)
promise.then(res => console.log('返回结果',res)) // []
// 如果某一个形参不需要用,用“_”占位
new Promise((_,reject) => {
reject('拒绝')
}).catch(err => console.log('错误',err)) // 拒绝
all类方法
Promise.all()将多个Promise包裹在一起形成一个新的Promise
新的Promise状态由包裹的所有Promise共同决定:
- 当所有Promise状态为fulfilled时,新的Promise状态为fulfilled,将所有Promise返回值组成一个数组
- 当有一个Promise状态为reject时,新的Promise状态为reject,会将第一个reject的返回值作为参数
const p1 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('p1 resole')
},2000)
})
const p2 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('p2 resole')
},3000)
})
// 等到所有的promise都有结果了之后再回调,结果会包裹成一个数组
// 中途有reject,直接回调catch方法
Promise.all([p1,p2])
.then(res => console.log('all promise',res)) // ['p1 resole', 'p2 resole']
.catch( err => console.log('出错了',err))
allSettled类方法
Promise.allSettled()在所有的Promise都有结果,无论是fulfilled,还是rejected时,才会有最终的状态; 并且这个Promise的结果一定是fulfilled的
const p1 = new Promise((resolve, reject) => {
setTimeout(() => {
reject('p1 reject')
}, 2000)
})
const p2 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('p2 resole')
}, 3000)
})
// 等到所有的promise都有结果,返回每一个promise的状态和结果
Promise.allSettled([p1, p2])
.then(res => console.log('all promise', res))
//[
// {status: 'rejected', reason: 'p1 reject'},
// {status: 'fulfilled', value: 'p2 resole'}
//]
race类方法
Promise.race()哪个Promise有了结果,就决定最终新Promise的状态
const p1 = new Promise((resolve, reject) => {
setTimeout(() => {
reject('p1 reject')
}, 2000)
})
const p2 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('p2 resole')
}, 3000)
})
// 谁先有结果就用谁的,只要有结果就会立马确定状态
Promise.race([p1, p2]).then(res => console.log('race resolve', res))
.catch(err => console.log('race catch:',err)) // race catch: p1 reject
any类方法
Promise.any()方法会等到一个fulfilled状态,才会决定新Promise的状态
如果所有的Promise都是reject,也会等到所有的Promise都变成rejected状态;内部会创建一个错误信息
总结
Proxy 和 Object.defineProperty的区别
Proxy:
- 设计初衷就是监听对象的改变,并且提供了多种方法监听对象的操作
- 拦截和监视外部对对象的访问
- 可以直接监听数组的变化
Object.defineProperty:
- 设计初衷是定义对象的属性,所以有些监听操作是监听不到的
- 对于复杂的对象,层级很深的话,需要深度监听
- 删除,添加属性是不能被监听的
- 不能监听数组的变化
Promise的作用和使用方法
- 是一个对象
- 对象的状态不受外界影响
- 一旦状态改变,就不会再变
- 异步编程的一种解决方案,比传统的解决方案--回调函数-更加合理和更强大