// 代理(Proxy)和反射(Reflection)
// 代理直接将所有操作直接转发到目标,将“proxy”赋值给proxy.name属性时会在目标上建立name,
// 代理只是简单的将操作转发给目标,他不会存储这个属性。由于proxy.name 和 target.name 引用的
// 都是 target.name 因此二者值相同
/*let target = {};
let proxy = new Proxy(target, {});
proxy.name = "proxy";
console.log(proxy.name);
console.log(target.name);
target.name = "target";
console.log(proxy.name);
console.log(target.name);*/
// 使用set陷阱验证属性
// 1. trapTarget 用于接收属性(代理的目标) 的对象
// 2. key 要写入的属性键(字符串或symbol类型)
// 3. value 被写入的属性的值
// 4. receiver 操作发生的对象 (通常是代理)
/*let target = {
name : "target"
};
let proxy = new Proxy(target, {
set(trapTarget, key, value, receiver) {
// 忽略已有属性
if(!trapTarget.hasOwnProperty(key)){
// 验证属性值 必须为数字
if(isNaN(value)){
throw new TypeError("属性必须是数字");
}
}
// 添加属性
return Reflect.set(trapTraget, key, value, receiver);
}
});
proxy.count = 1;
console.log(proxy.count); // 1
console.log(target.count); // 1
// 这是因为属性值 是数字 所以可以添加count属性到target上
// 由于已有的name属性 因而可以直接给他赋值
proxy.name = "proxy";
console.log(proxy.name); // “proxy"
console.log(target.name); // "proxy"
proxy.anotherName = " wujiahui "; // 会抛出错误 因为属性值是非数字*/
// 用get 陷阱验证对象结构(Object Shape)
// 1. trapTarget 被读取属性的源对象 (代理的目标)
// 2. key 要读取的属性键 (字符串或symbol)
// 3. receiver 操作发生的对象 (通常是代理)
/* let proxy = new Proxy({}. {
get(trapTarget, key, receiver) {
if(!(key in receiver)) {
throw new TypeError("属性" + key + "不存在");
}
return Reflect.get(trapTraget, key, recevier);
}
});
// 如果属性不存在会抛出错误 (对比在对象中 属性不存在抛出 undefined)
console.log(proxy.name); // 抛出错误 */
// 属性描述符陷阱
// defineProperty 陷阱接收以下参数
// 1. trapTarget 要定义属性的对象
// 2. key 属性的键 (字符串或symbol)
// 3. descriptor 属性的描述符对象
/*let proxy = new Proxy({}, {
defineProperty(tarpTarget, key, descriptor) {
return Reflect.defineProperty(trapTarget, key, descriptor);
},
getOwnPropertyDescriptor(trapTarget, key) {
return Reflect.getOwnPropertyDescriptor(trapTarget, key);
}
});
Object.defineProperty(proxy, "name", {
value: "Proxy"
});
console.log(proxy.name); // "proxy"
let descriptor = Object.getOwnPropertyDescriptor(proxy, name);
console.log(descriptor.value); // "proxy"*/
// 函数代理中的apply 和 construct陷阱
// Reflect.construct 和 Reflect.apply 接收以下参数
// 1. trapTarget 被执行的函数(代理的目标)
// 2. thisArg 函数被调用时内部this的值
// 3. argumentsList 传递给函数的参数数组
// 当使用new调用函数时调用的construct 陷阱接收以下参数
// 1. trapTarget 被执行的函数(代理的目标)
// 2. argumentsList 传递给函数的参数数组
/* let target = function() { return 42; },
proxy = new Proxy(target, {
apply: function(trapTarget, thisArg, argumentsList) {
return Reflect.apply(trapTarget, thisArg, argumentsList);
},
construct: function(trapTarget, argumentsList) {
return Reflect.construct(trapTarget, argumentsList);
}
});
// 一个目标是函数的代理看起来也像一个函数
console.log(typeof proxy); // "function"
console.log(proxy()); // 42
var instance = new proxy();
console.log(instance instanceof proxy); // true
console.log(instance instanceof target); // true
*/
/*在这里,有一个返回数字42的函数,该函数的代理分别使用apply陷阱和construct陷阱来
将那些行为委托给Reflect.apply()方法和Reflect.construct()方法。最终结果是代理函数
与目标函数完全相同,包括在使用typeof时将自己标识为函数。不用new调用代理时返回42,
用new调用时创建一个instance对象,它同时是代理和目标的实例,因为instanceof通过原型
链来确认此信息。而原型链查找不受代理影响。这也就是代理和目标好像有相同原型的原因。
*/
// 检测数组索引
// 当且仅当ToString(ToUnit32(p)) 等于p,并且ToUnit32(p)不等于2^32 -1 ,字符串属性名称
// p才是一个数组的索引
/* function toUnit32(value) {
return Math.floor(Math.abs(Number(value))) % Math.pow(2, 32);
}
function isArrayIndex(key) {
let numerickey = toUnit32(key);
return String(numerickey) == key && numerickey < (Math.pow(2, 32) -1 );
}*/