1 Proxy 代理
1.1 Es5 代理
let obj = {};
let newVal = '';
Object.defineProperty(obj, 'name', {
get(){
return newVal;
},
set(v){
newVal = v;
// this.name = v 如果這樣寫,,會(huì)無限觸發(fā)set
}
});
obj.name = 123;
console.log(obj.name); // 123
1.2 Es6 代理
1.2.1 基礎(chǔ)用法
let obj = {};
let p = new Proxy(obj,{});
obj.name = 123
console.log(p.name); // 123
1.2.2 get 方法 監(jiān)聽屬性讀取
舉例說明
let dict = {
'xx' : 'xx'
};
dict = new Proxy(dict, {
get(target, p, receiver){
// target : Object xx: "xx"
// p : 傳進(jìn)來的xx
// receiver : Proxy
return '自定義條件 賽選以后返回的值';
}
});
console.log(dict['xx']); // 自定義條件 賽選以后返回的值
1.2.3 set方法 監(jiān)聽設(shè)置屬性
舉例 : 只能設(shè)置number類型
必須返回一個(gè)boolean類型
let dict = {
'xx' : 'xx'
};
dict = new Proxy(dict, {
set(target, p, value, receiver){
console.log(target, p, value, receiver);
return true
打印結(jié)果 : {xx: "xx"} "xx" "123" Proxy {xx: "xx"}
}
});
dict['xx'] = '123';
1.2.4 has方法 判斷key是否在對(duì)象里面
let range = {
start : 1,
end : 10
};
// console.log(2 in range); // false,此時(shí)沒被代理
range = new Proxy(range, {
has(target, p){
console.log(target, p); // {start: 1, end: 10} "2"
return p >= target.start && p <= target.end;
}
});
console.log(2 in range); //true
console.log(11 in range); //false
1.2.5 ownkeys 方法 監(jiān)聽循環(huán)遍歷
let obj = {
name : 'xxx',
[Symbol('es')] : 'es6'
};
Object.getOwnPropertyNames(obj); // ["name"] 非Symbol類型
Object.keys(obj); // ["name"] 非Symbol類型
for(let key in obj){console.log(key);} // name
Object.getOwnPropertySymbols(obj); // [Symbol(es)] Symbol
舉例,,,設(shè)置以 _ 開頭的字段,,為私有屬性
let userName = {
name : 'xx',
age : 18,
_passWord : '***'
};
userName = new Proxy(userName, {
ownKeys(target){
return Object.keys(target)
.filter(key => {
// console.log(key); // name age _passWord
return !key.startsWith('_');
});
}
});
for(let userNameKey in userName){
console.log(userNameKey); // name age
}
1.2.6 deleteProperty 方法 攔截delete方法
必須返回一個(gè)boolean類型
let userName = {
name : 'xx',
age : 18,
_passWord : '***'
};
userName = new Proxy(userName, {
deleteProperty(target, p){
// 是否以下劃線開頭
if(p.startsWith("_")){
delete target[p]
}
}
});
delete userName["age"]
console.log(userName); // {name: "xx", age: 18, _passWord: "***"}
delete userName["_passWord"]
console.log(userName); // {name: "xx", age: 18}
1.2.7 apply方法 攔截函數(shù)的調(diào)用,,以及call,apply等
一個(gè)求和函數(shù)
let GetSum = (...args) => {
let num = 0;
args.forEach(item => {
num += item;
});
return num;
};
GetSum = new Proxy(GetSum, {
apply(target, thisArg, argArray){
console.log(target); // GetSum函數(shù)
console.log(thisArg); // GetSum(1, 2): undefined
console.log(argArray); // [1, 2] GetSum的參數(shù)
return target(...argArray) * 2;
}
});
GetSum(1, 2); // 6 代理以后*2
GetSum.call(null, 1, 2); // 6 代理以后*2 第一個(gè)參數(shù)是指向的對(duì)象
GetSum.apply(null, [1, 2, 3]); // 12 第一個(gè)參數(shù)是指向的對(duì)象 第二個(gè)是數(shù)組
1.2.8 construct方法 攔截new
let newClass = class{
constructor(name){
this.name = name;
}
};
newClass = new Proxy(newClass, {
construct(target, argArray, newTarget){
console.log(target); // newClass這個(gè)的class
console.log(argArray); // ["xx"] 參數(shù)的數(shù)組
console.log(newTarget); // {length: 1, prototype: {…}, name: "newClass"}
return new target('我改變了參數(shù)');
}
});
let a = new newClass('xx');
console.log(a); // newClass {name: "我改變了參數(shù)"}
1.2.9 proxy總結(jié)
2 Reflect反射
2.1 將Object的語法轉(zhuǎn)移到Reflect上面
設(shè)計(jì)之初,很多方法都掛載在Object上面,,es6轉(zhuǎn)移一部分到Reflect
Object.defineProperty => Reflect.defineProperty
2.2 修改某些Object方法的返回值
Object.defineProperty (沒有返回值) 去定義屬性 如果有些屬性無法被定義 :
如果不能被定義拋出異常
try{
Object.defineProperty()
}catch(e){
}
Reflect.defineProperty有返回值(布爾類型),,,如果不能定義返回false
2.3 讓Object操作變成函數(shù)行為
"assign" in Object // true Object下面 是否有assign這個(gè)方法
Reflect.has(Object,"assign") // true
2.3 Reflect對(duì)象的方法和Proxy對(duì)象的方法一一對(duì)應(yīng)
get set delete ownKeys
let user = {
name : 'xx',
_passWord : '123456'
};
user = new Proxy(user, {
get(target, p, receiver){
if(p.startsWith('_')){
throw new Error('不可訪問');
} else{
// return target[p] 和下面的這種寫法一樣
return Reflect.get(target, p);
}
},
set(target, p, value, receiver){
// target[p] = value
if(p.startsWith('_')){
throw new Error('不可訪問');
} else{
Reflect.set(target, p, value);
return true;
}
},
deleteProperty(target, p){
if(p.startsWith('_')){
throw new Error('不可訪問');
} else{
// delete target[p]
Reflect.defineProperty(target, p);
return true;
}
},
ownKeys(target){
return Object.keys(target)
.filter(key => {
// console.log(key); // name age _passWord
return !key.startsWith('_');
});
// 可直接把Object.keys換成 Reflect.keys
},
});
// get
console.log(user.name); // xx
try{
console.log(user._passWord);
} catch(e){
console.log(e.message);
} // 會(huì)打印不可訪問
// set
user.name = 11;
console.log(user.name); // 11
try{
user._passWord = 11;
} catch(e){
console.log(e.message);
} // 會(huì)打印不可訪問
// delete 與上一致
apply
let getSum = (...args) => {
let num = 0;
args.forEach((item) => {
num += item;
});
return num;
};
console.log(getSum(1, 2)); // 3
getSum = new Proxy(getSum, {
apply(target, thisArg, argArray){
// return target(...argArray) * 2;
// 改變誰,,,改變成誰,,,參數(shù)
return Reflect.apply(target, target, [...argArray]) * 2;
}
});
console.log(getSum(1, 2)); // 6
console.log(getSum.apply(null, [1, 2])); // 6