1.20(Proxy、Reflect、异步)
一、代理
1、es5代理
let obj1 = {};
let newVal = '';
Object.defineProperty(obj1, 'name', {
get () {
return newVal;
},
set (val) {
console.log(val);//es
newVal = val;
}
})
obj1.name = 'es';
console.log(obj1.name);//es
2、Proxy(代理对象,配置)
let obj2 = {};
let p = new Proxy(obj2, {});
p.name = 'wuyan';
console.log(obj2.name);//wuyan
for(let key in obj2) {
console.log(key);//name
}
2.1 数组代理方式
let arr1 = [7, 8, 9];
arr1 = new Proxy(arr1, {
// 钩子函数get
get(target, prop) {
console.log(target, prop);
//[7, 8, 9] "2"
//[7, 8, 9] "10"
//如果索引在数组里有对应的值则返回,否则报错
return prop in target ?target[prop]: 'error';
},
})
// 想获取对象里的属性时,代理就会使用get来处理
console.log(arr1[2]);//9
console.log(arr1[10]);//error
let arr2 = [];
arr2 = new Proxy(arr2, {
//钩子函数set
set(target, prop, val) {
if(typeof val === 'number') {
target[prop] = val;
return true;
} else {
return false;
}
}
})
arr2.push(5);
arr2.push(6);
console.log(arr2[0],arr2[1],arr2.length);
2.2 对象代理
let dict = {
'hello':'你好',
'world':'世界'
}
dict = new Proxy(dict, {
get (target, prop) {
return prop in target ?target[prop] : prop;
}
})
console.log(dict['hello']);//你好
2.3 has
let range = {
start:1,
end:5
}
range = new Proxy(range, {
has(target, prop) {
return prop >= target.start && prop <= target.end;
}
})
console.log(2 in range);//true
console.log(9 in range);//false
//ownKeys 对于循环遍历进行拦截操作
let obj3 = {
name:'wuyan',
[Symbol('es')]:'es6'
}
console.log(Object.getOwnPropertyNames(obj3));//name
console.log(Object.getOwnPropertySymbols(obj3));//Symbol(es)
console.log(Object.keys(obj3));//name
for(let key in obj3) {
console.log(key);//name
}
let userinfo = {
username:'wuyan',
age:22,
_password:'***'
}
userinfo = new Proxy(userinfo, {
// 循环
ownKeys(target) {
// Object.keys()取出对象属性
//filter()返回符合func条件的元素数组
// 这边不返回_password
return Object.keys(target).filter(key => !key.startsWith('_'));
}
})
for(let key in userinfo){
console.log(key);//1、username 2、age
}
console.log(Object.keys(userinfo));//[username, age]
2.4 整合起来
let user = {
name:'wuyan',
age:34,
_password:'******'
}
user = new Proxy(user, {
//需求:不能对_password进行任何操作
//get
get(target, prop) {
if(prop.startsWith('_')) {
/* throw语句用来抛出一个用户自定义的异常。当前函数的执行将被
停止(throw之后的语句将不会执行),并且控制将被传递到调用
堆栈中的第一个catch块。如果调用者函数中没有catch块,程序
将会终止。 */
throw new Error('不可访问');
/*
通过Error的构造器可以创建一个错误对象。当运行时错误产生时,
Error的实例对象会被抛出。Error对象也可用于用户自定义的异常
的基础对象。下面列出了各种内建的标准错误类型。
*/
} else {
return target[prop];
}
},
//set
set (target, prop, val) {
if(prop.startsWith('_')) {
throw new Error('不可修改');
} else {
target[prop] = val;
return true;
}
},
//delete
deleteProperty(target, prop) {
if (prop.startsWith('_')) {
throw new Error('不可删除');
} else {
delete target[prop];
return true;
}
},
//repeat
ownKeys(target) {
return Object.keys(target).filter(key => !key.startsWith('_'));
}
})
console.log(user.age);//34
//console.log(user._password);
user.age = 22;
console.log(user.age);//22
try {
user._password = 222;
} catch (error) {
console.log(error.message);//不可修改
}
try {
delete user._password;
} catch (error) {
console.log(error.message);//不可删除
}
for(let key in user) {
console.log(key);//name age
}
2.5 apply
let sum = (...args) => {
let num = 0;
args.forEach(item => {
num += item;
})
return num;
}
sum = new Proxy(sum, {
apply(target, ctx, args) {
return target(...args) * 2;
}
})
console.log(sum(1, 2));//6
console.log(sum.call(null, 1, 2, 3));//12
console.log(sum.apply(null, [1, 2, 3]));//12
2.6 construct new
let User = class {
constructor(name) {
this.name = name;
}
}
User = new Proxy(User, {
construct(target, args, newTarget) {
console.log('拦截被执行');
return new target(...args);
}
})
console.log(new User('wuyan'));
二、反射
1、将Object方法转到Reflect上(ES5)
let obj1 = {};
let newVal = '';
Reflect.defineProperty(obj1, 'name', {
get () {
return newVal;
},
set (val) {
console.log(val);//es
newVal = val;
}
})
obj1.name = 'es';
console.log(obj1.name);//es
2、修改某些Object方法的返回结果,让其变得更合理
// try {
// Object.defineProperty()
// } catch (e) {}
// if(Reflect.defineProperty()){//boolean
// } else {
// }
3、让Object操作变成函数行为(ES6)
let user = {
name:'wuyan',
age:34,
_password:'******'
}
user = new Proxy(user, {
//需求:不能对_password进行任何操作
//get
get(target, prop) {
if(prop.startsWith('_')) {
/* throw语句用来抛出一个用户自定义的异常。当前函数的执行将被
停止(throw之后的语句将不会执行),并且控制将被传递到调用
堆栈中的第一个catch块。如果调用者函数中没有catch块,程序
将会终止。 */
throw new Error('不可访问');
/*
通过Error的构造器可以创建一个错误对象。当运行时错误产生时,
Error的实例对象会被抛出。Error对象也可用于用户自定义的异常
的基础对象。下面列出了各种内建的标准错误类型。
*/
} else {
// return target[prop];
return Reflect.get(target, prop);
}
},
//set
set (target, prop, val) {
if(prop.startsWith('_')) {
throw new Error('不可修改');
} else {
Reflect.set(target, prop, val);
return true;
}
},
//delete
deleteProperty(target, prop) {
if (prop.startsWith('_')) {
throw new Error('不可删除');
} else {
Reflect.deleteProperty(target,prop);
return true;
}
},
//repeat
ownKeys(target) {
return Reflect.ownKeys(target).filter(key => !key.startsWith('_'));
}
})
console.log(user.age);//34
//console.log(user._password);
try {
console.log(user._password);
} catch (error) {
console.log(error.message);
}
try {
user._password = 'xxx';
} catch (error) {
console.log(error.message);
}
try {
delete user._password;
} catch (error) {
console.log(error.message);
}
for(let key in user) {
console.log(key);
}
4、Reflect对象的方法与Proxy对象的方法一一对应
let sum = (…args) => {
let num = 0;
args.forEach(item => {
num += item;
})
return num;
}
sum = new Proxy(sum, {
apply(target, ctx, args) {
return Reflect.apply(target, target, […args]) * 2;
}
})
console.log(sum(1, 2));//6
console.log(sum.call(null, 1, 2, 3));//12
console.log(sum.apply(null, [1, 2, 3]));//12
[自学中,有错误欢迎指正]