ES6之Proxy的get方法详解


Posted in Javascript onOctober 11, 2019

Proxy是在ES2015(ES6)中新添加内置对象,用于自定义一些基本操作。

这篇文章是我在学习Proxy的时候对于get方法的一些心得。

作为ES2015新定义的内置对象,Proxy 能够拦截并且自定义对象以及函数的一些基本操作,具有很高的优先级和便利性,能够让我们在写代码的时候多出一种解决难题的途径。

Proxy的get方法用于拦截对象属性的读取操作,例如 obj.key 和 obj.[key]。在给Proxy的handler参数中设置get方法后,每当进行读取操作时,会优先调用该get方法,我们可以在这个方法函数中对读取行为进行拦截。请看下面的代码:

const obj = { key: 1 }
const proxy = new Proxy(obj, {
 get: function(target, property, receiver) {
  console.log('get', property)
  return target[property]
 }
})
console.log(proxy.key)
// get key
// 1

get方法的参数一共有三个:target是实例化Proxy时使用的对象,在这个例子中是obj;而property是这次读取操作中想要获取的属性名,在这个例子中是key;最后一个参数receiver则是这个实例化的Proxy自身,即proxy。
在这个例子中,我在get方法的最后返回了target[property],这是为了能够让读取操作能够进行下去。由于Proxy的get方法是最先被调用的,所以这里返回的内容就是我们读取操作能够获得的结果;如果我们在这里不返回任何值,那么就会得到undefined。

receiver和死循环

要注意的是,千万不要在get方法中读取receiver的属性,因为receiver实质上就是proxy自身,所以receiver.key这句代码就等同于proxy.key,会重新调用get方法导致死循环。

const obj = { key: 1 }
const proxy = new Proxy(obj, {
 get: function(target, property, receiver) {
  console.log(receiver.key)
  return target[property]
 }
})
console.log(proxy.key)
// 死循环!

原型链上的getter

有时候,我们会在对象之中使用getter和setter来定制属性的赋值和读取。在这时,如果proxy的get方法内部有使用到target[property]的话,target[property]的值会受到目标对象的getter的影响。因此调用get方法的时候请注意在目标对象中是否有用到getter。

const obj = {
 get key() {
  return 'string'
 },
 set key(value) {
  console.log(`key is ${value}, it is a ${typeof value}`)
 }
}
const proxy = new Proxy(obj, {
 get: function(target, property, receiver) {
  if(typeof target[property] !== 'string') {
   return target[property]
  } else {
   throw new TypeError(`The type of ${property} is String!`)
  }
 }
})
proxy.key = 100
console.log(proxy, obj)
// key is 100, it is a number
// The type of key is String!

在上方的例子中,如果访问obj的非数字类型的属性,就会抛出一个错误,但是由于obj中getter的原因,无论我给key属性赋什么值,在访问key属性的时候肯定会抛出错误。

如果仅仅要注意目标对象中的getter还算容易的,但是如果目标对象继承自其他对象,那么事情就变得有些麻烦了,请看下面的例子:

const parentObj = {
 get key() {
  return 'string'
 },
 set key(value) {
  console.log(`key is ${value}, it is a ${typeof value}`)
 }
}
const obj = Object.create(parentObj)
const proxy = new Proxy(obj, {
 get: function (target, property, receiver) {
  if (typeof target[property] !== 'string') {
   return target[property]
  } else {
   throw new TypeError(`The type of ${property} is String!`)
  }
 }
})
proxy.key = 100 
console.log(proxy.key)
// key is 100, it is a number
// The type of key is String!

如代码所示,目标对象obj继承自parentObj,而parentObj中使用了getter方法,那么使用proxy的get方法仍旧会报错。实际运用中原型链可能会很长,getter可能会存在于原型链的任何一个地方中,所以在使用Proxy的get方法时请一定要注意。

但是如果把parentObj上的key遮蔽掉,就不会发生抛出错误的情况了。比如在创建obj的时候申明的key,代码如下:

const parentObj = {
 get key() {
  return 'string'
 },
 set key(value) {
  console.log(`key is ${value}, it is a ${typeof value}`)
 }
}
const obj = Object.create(parentObj, {
 key: {
  value: null,
  writable: true
 }
})
const proxy = new Proxy(obj, {
 get: function (target, property, receiver) {
  if (typeof target[property] !== 'string') {
   return target[property]
  } else {
   throw new TypeError(`The type of ${property} is String!`)
  }
 }
})
proxy.key = 100 
console.log(proxy.key)
// 100

同样的,我们也可以使用Object.defineProperty()和Object.assign()这两个方法来达到相同的目的:

Object.defineProperty(obj, 'key', {
 value: null,
 writable: true
})
obj = Object.assign({}, obj, { key: null })

但是要注意使用Object.assign()的时候不能这么些:

obj = Object.assign(obj, { key: null })

这样写法无法遮蔽掉parentObj上的key属性,使用的时候仍旧会抛出错误。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
基于jquery的一个浮动框(扩展性比较好 )
Aug 27 Javascript
Jquery AJAX POST与GET之间的区别
Nov 14 Javascript
jQuery实现可用于博客的动态滑动菜单
Mar 09 Javascript
js实现防止被iframe的方法
Jul 03 Javascript
表单中单选框添加选项和移除选项
Jul 04 Javascript
jQuery增加、删除及修改select option的方法
Aug 19 Javascript
JavaScript之排序函数_动力节点Java学院整理
Jun 30 Javascript
Sublime Text新建.vue模板并高亮(图文教程)
Oct 26 Javascript
vue 动态修改a标签的样式的方法
Jan 18 Javascript
微信小程序tabbar底部导航
Nov 05 Javascript
浅谈laytpl 模板空值显示null的解决方法及简单的js表达式
Sep 19 Javascript
Node绑定全局TraceID的实现方法
Nov 14 Javascript
vue组件 keep-alive 和 transition 使用详解
Oct 11 #Javascript
jquery将json转为数据字典的实例代码
Oct 11 #jQuery
JavaScript实现抖音罗盘时钟
Oct 11 #Javascript
javascript刷新父页面方法汇总详解
Oct 10 #Javascript
element form 校验数组每一项实例代码
Oct 10 #Javascript
使用Vue-cli3.0创建的项目 如何发布npm包
Oct 10 #Javascript
js判断复选框是否选中的方法示例【基于jQuery】
Oct 10 #jQuery
You might like
PHP 网页过期时间的控制代码
2009/06/29 PHP
兼容各大浏览器带关闭按钮的漂浮多组图片广告代码
2014/06/05 PHP
php 输出json及显示json中的中文汉字详解及实例
2016/11/09 PHP
php脚本守护进程原理与实现方法详解
2017/07/20 PHP
phpStudy2016 配置多个域名期间遇到的问题小结
2017/10/19 PHP
PHP钩子实现方法解析
2019/05/21 PHP
iframe自适应宽度、高度 ie6 7 8,firefox 3.86下测试通过
2010/07/29 Javascript
关于JS管理作用域的问题
2013/04/10 Javascript
给Flash加一个超链接(推荐使用透明层)兼容主流浏览器
2013/06/09 Javascript
鼠标移到图片上变大显示而不是放大镜效果
2014/06/15 Javascript
MVVM模式中ViewModel和View、Model有什么区别?
2015/06/19 Javascript
jQuery实现仿QQ头像闪烁效果的文字闪动提示代码
2015/11/03 Javascript
jQuery实现的简单分页示例
2016/06/01 Javascript
AngularJs学习第八篇 过滤器filter创建
2016/06/08 Javascript
Angular外部使用js调用Angular控制器中的函数方法或变量用法示例
2016/08/05 Javascript
JavaScript面向对象编写购物车功能
2016/08/19 Javascript
Vue数据监听方法watch的使用
2018/03/28 Javascript
jQuery实现ajax回调函数带入参数的方法示例
2018/06/26 jQuery
jQuery超简单遮罩层实现方法示例
2018/09/06 jQuery
jquery实现轮播图特效
2020/04/12 jQuery
JavaScript中layim之整合右键菜单的示例代码
2021/02/06 Javascript
python使用Flask框架获取用户IP地址的方法
2015/03/21 Python
Python实现PS滤镜功能之波浪特效示例
2018/01/26 Python
Python常用数据类型之间的转换总结
2019/09/06 Python
python 利用已有Ner模型进行数据清洗合并代码
2019/12/24 Python
详解使用Python写一个向数据库填充数据的小工具(推荐)
2020/09/11 Python
Python 实现集合Set的示例
2020/12/21 Python
职高毕业生自我鉴定
2013/10/21 职场文书
采购员岗位职责
2013/11/15 职场文书
模具设计与制造专业推荐信
2014/02/16 职场文书
《凡卡》教学反思
2014/04/09 职场文书
学校党的群众路线教育实践活动制度建设计划
2014/11/03 职场文书
党的群众路线教育实践活动个人对照检查材料(校长)
2014/11/05 职场文书
大学生操行评语大全
2014/12/31 职场文书
nginx常用命令放入shell脚本详解
2021/03/31 Servers
详解Python为什么不用设计模式
2021/06/24 Python