Proxy&Reflect
大部分时候我们使用的都是前置代理, 即我们把直接和代理对象进行交互(所有操作都发生在代理对象身上)的方式叫做前置代理. 那什么是后置代理?
借助原型链机制, 我们直接和 obj 进行交互而不是和代理对象进行交互, 只有当 obj 不存在对应方法时才会通过原型链去查找代理对象.
var pobj = new Proxy({}, {
get(target, key) {
if (!target[key]) { //若target[key]不存在;则这里不应该写在target上,应该写在Obj上,这样下次就不用再次进入原型链的代理里面了
target[key] = function () {
console.log(key);
};
}
return target[key];
}
});
var obj = Object.create(pobj);
obj.sayHello();
obj.sayGoodBye();
Reflect 的方法和 Proxy 的方法是成对出现的, 和以前的一些方法相比, Reflect 的方法对参数的处理不同或返回值不同, 尽管很细微的差别, 但是当和 Proxy 配合使用的时候, 使用以前的方法可能导致 Proxy 对象和普通对象的一些行为不一致, 而使用 Reflect 则不会有这样的问题, 所以建议在 Proxy 中都使用 Reflect 的对应方法.Reflect 暴露的 API 相对更加底层, 性能会好一些.Reflect 实现, 具体参考这个例子. 但是个人感觉这个例子并不是很好, 毕竟这个场景太少见了.var pobj = new Proxy({}, {
get(target, key) {
if (!target[key]) {
target[key] = function () {
console.log(key);
};
}
return target[key];
}
});
var obj = Object.create(pobj);
obj.sayHello();
obj.sayGoodBye();
//在这个例子中, 调用 obj 上一开始不存在的方法最终都会通过原型链找到代理对象, 进而找到 target 也即空对象, 然后对空对象实例化对应的方法.
//这里的原型链查找总是让人感觉不太爽, 明明进入到 get trap 就肯定说明 obj 一开始不存在对应方法, 那我们理应可以在这时候给 obj 设置对应方法,
//这样下次调用的时候就不会进行原型链的查找了, 为什么非要给那个毫无卵用的空对象设置方法, 导致每次对 obj 进行方法调用还是要进行原型链查找?
改成receiver[key]
var pobj = new Proxy({}, {
get(target, key, receiver) {
if (!receiver[key]) {
receiver[key] = function () {
console.log(key);
};
}
return receiver[key];
}
});
var obj = Object.create(pobj);
obj.sayHello();
// RangeError: Maximum call stack size exceeded 栈溢出
//因为obj.sayHello obj对内没这个属性 => 通过原型链 到proxy的get 里面找 receiver[key] ==obj['sayHello'] =>又循环 一直调用导致stack内存溢出
若用receiver.hasOwnProperty(key)一样会死循环;用reflect.has去判断是否有该属性,reflect更底层不会向之前那个通过obj去找实例或者原型上的方法导致循环调用
var pobj = new Proxy({}, {
get(target, key, receiver) {
if (!receiver.hasOwnProperty(key)) {
receiver[key] = function () {
console.log(key);
};
}
return receiver[key];
}
});
var obj = Object.create(pobj);
obj.sayHello();
// RangeError: Maximum call stack size exceeded
//还是堆栈溢出, 因为 hasOwnProperty() 其实是 Object.prototype.hasOwnProperty(), 意味着在原型链的尽头, 而 pobj 在原型链上更近的位置,
//于是相当于 receiver/obj 并不存在 hasOwnProperty(), 于是变成了对 obj.hasOwnProperty() 无限查找导致堆栈溢出.
用call解决
var pobj = new Proxy({}, {
get(target, key, receiver) {
if (!Object.prototype.hasOwnProperty.call(receiver, key)) {
receiver[key] = function () {
console.log(key);
};
}
return receiver[key];
}
}); var obj = Object.create(pobj);
obj.sayHello();
obj.sayHello();
// sayHello
// sayHello
若用reflect解决更好
var pobj = new Proxy({}, {
get(target, key, receiver) {
if (Reflect.has(target, key)) {
return Reflect.get(target, key);
}
Reflect.set(receiver, key, function () {
console.log(key);
});
return Reflect.get(receiver, key);
}
});
var obj = Object.create(pobj);
obj.sayHello();
obj.sayHello();
console.log(obj.hasOwnProperty('sayHello'));
参考:https://juejin.im/post/5b7aa257e51d4538c86cf6bb#heading-2
Proxy&Reflect的更多相关文章
- es6(11)--Proxy,Reflect
//Proxy,Reflect { let obj={ time:'2018-06-25', name:'net', _r:123 }; let monitor = new Proxy(obj,{ / ...
- ES6走一波 Proxy/Reflect
Proxy:像拦截器,对目标对象修改等进行拦截,是一种元编程(meta programming),即修改JS语言本身. //生成proxy实例,两个参数都是对象,targetObj是要拦截的目标对象, ...
- ES6中的元编程-Proxy & Reflect
前言 ES6已经出来好久了,但是工作中比较常用的只有let const声明,通过箭头函数改this指向,使用promise + async 解决异步编程,还有些数据类型方法...所以单独写一篇文章学习 ...
- [ES6] Proxy & Reflect
Proxy and Reflect API works nicely together. About how to use Proxy, check this post. Let's see abou ...
- Proxy + Reflect 实现 响应的数据变化
Proxy 对象用于定义基本操作的自定义行为(如属性查找,赋值,枚举,函数调用等) let p = new Proxy(target, handler); get(target, propKey, r ...
- es6总结(七)--proxy & reflect
- 2、数据结构 proxy 代理 reflect 反射
增删改查 1.set (数组) 2.map (对象 key value) 数据结构横向对比 map.set('t',1) arr.push({t:1}) set.add({t:1}) arr.push ...
- 利用ES6中的Proxy和Reflect 实现简单的双向数据绑定
利用ES6中的Proxy (代理) 和 Reflect 实现一个简单的双向数据绑定demo. 好像vue3也把 obj.defineProperty() 换成了Proxy+Reflect. 话不多说 ...
- ES6入门:数据劫持、Proxy、Reflect
什么是数据劫持 Object数据劫持实现原理 Array数据劫持的实现原理 Proxy.Reflect 一.什么是数据劫持 定义:访问或者修改对象的某个属性时,在访问和修改属性值时,除了执行基本的数据 ...
随机推荐
- SpringBoot启动时的Banner设置
Spring Boot程序启动的时候输出的由字符组成的Spring符号并不陌生.这个是Spring Boot为自己设计的Banner: 1. 第一种方式:修改的时候,进行设置,在Application ...
- 使用oracle删除表中重复记录
(1)使用用rowid方法 查询重复数据:select * from person a where rowid !=(select max(rowid) from person b where a.c ...
- spring的AOP——采用注解完成AOP
AOP的两种配置方式:XML配置和Aspectj注解方式. 一.项目的目录: 二.文件配置 我们采用的是JDK代理,所以首先将接口和实现类代码附上: public interface UserMana ...
- 按模版导出Excel
实现效果: excel模版: ExcelHandle.java package com.common.utils; import java.io.File; import java.io.FileIn ...
- fstab中使用设备的uuid
设备定位的方法有: 设备名称, 如:/dev/sda1, 随着linux内核加载模块顺序在每次启动的时候可能会不同, 在插拔U盘/移动硬盘的时候, 设备分配到的名称可能不同,这样fs映射就会失败 因此 ...
- vscode + php+ftp
首先,php网站的文件都整理到一个文件夹中: 然后,用vscode的File.Open Folder打开刚才的文件夹: 3,Ctrl+Shift+P,输入SFTP:Config,会打开一个配置文件,编 ...
- jenkins与docker(DevOps二)
Jenkins官网 https://jenkins.io/download/ centos 7安装Docker https://www.cnblogs.com/stulzq/p/7743073.htm ...
- Linux下源码安装MySQL-5.6.25
从mysql-5.5起,mysql源码安装开始使用cmake了,因此我们得先安装cmake,配置安装目录./configure --perfix=/.....的时候和以前的会有些区别. 一.安装cma ...
- 使用ssh-agent管理私钥
使用ssh-agent的好处: 如果有多台远程服务器与多个私钥文件,ssh-gent将会尝试使用不同的私钥文件建立连接,直至成功 假如有 A.B.C 三台服务器,A是控制节点,A可以直接登录B,但是无 ...
- python基础-python函数参数为print语句时的输出
函数参数输入print语句,调用函数时都会执行print语句,实例: def outer(func): def inner(): print("我是内层函数!") return i ...