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数组封装使用方法分享(jquery数组遍历)
Mar 25 Javascript
struts2+jquery组合验证注册用户是否存在
Apr 30 Javascript
angularJS 中$attrs方法使用指南
Feb 09 Javascript
JavaScript的9种继承实现方式归纳
May 18 Javascript
值得分享的bootstrap table实例
Sep 22 Javascript
基于Vue2.0的分页组件
Mar 16 Javascript
JavaScript实现的原生态兼容IE6可调可控滚动文字功能详解
Sep 19 Javascript
es6新特性之 class 基本用法解析
May 05 Javascript
浅谈Layui的eleTree树式选择器使用方法
Sep 25 Javascript
javascript sort()对数组中的元素进行排序详解
Oct 13 Javascript
JavaScript常用工具函数大全
May 06 Javascript
详解uniapp的全局变量实现方式
Jan 11 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 sdk实现在线打包代码示例
2020/12/09 PHP
深入认识JavaScript中的函数
2007/01/22 Javascript
麻雀虽小五脏俱全 Dojo自定义控件应用
2010/09/04 Javascript
基于JavaScript实现 获取鼠标点击位置坐标的方法
2013/04/12 Javascript
使用PHP+JQuery+Ajax分页的实现
2013/04/23 Javascript
jQuery 借助插件Lavalamp实现导航条动态美化效果
2013/09/27 Javascript
javascript中的nextSibling使用陷(da)阱(keng)
2014/05/05 Javascript
Node.js入门教程:在windows和Linux上安装配置Node.js图文教程
2014/08/14 Javascript
js字符串完全替换函数分享
2014/12/03 Javascript
Javascript 拖拽雏形中的一些问题(逐行分析代码,让你轻松了拖拽的原理)
2015/01/23 Javascript
jquery实现点击向下展开菜单项(伸缩导航)效果
2015/08/22 Javascript
bootstrap滚动监控器使用方法解析
2017/01/13 Javascript
gulp解决跨域的配置文件问题
2017/06/08 Javascript
使用 vue 实例更好的监听事件及vue实例的方法
2019/04/22 Javascript
10个最受欢迎的 JavaScript框架(推荐)
2019/04/24 Javascript
JavaScript函数式编程(Functional Programming)高阶函数(Higher order functions)用法分析
2019/05/22 Javascript
Vue过渡效果之CSS过渡详解(结合transition,animation,animate.css)
2020/02/05 Javascript
如何搭建一个完整的Vue3.0+ts的项目步骤
2020/10/18 Javascript
JavaScript事件概念详解(区分静态注册和动态注册)
2021/02/05 Javascript
Python StringIO模块实现在内存缓冲区中读写数据
2015/04/08 Python
Python的Flask框架中SQLAlchemy使用时的乱码问题解决
2015/11/07 Python
python使用matplotlib绘制折线图教程
2017/02/08 Python
Python使用defaultdict读取文件各列的方法
2017/05/11 Python
python matplotlib坐标轴设置的方法
2017/12/05 Python
Django使用httpresponse返回用户头像实例代码
2018/01/26 Python
PyTorch搭建多项式回归模型(三)
2019/05/22 Python
python做反被爬保护的方法
2019/07/01 Python
python GUI库图形界面开发之PyQt5切换按钮控件QPushButton详细使用方法与实例
2020/02/28 Python
Python3爬虫中关于Ajax分析方法的总结
2020/07/10 Python
Python pip 常用命令汇总
2020/10/19 Python
Aeropostale官网:美国著名校园品牌及青少年服饰品牌
2019/03/21 全球购物
科颜氏印度官网:Kiehl’s印度
2021/02/20 全球购物
企划主管岗位职责
2013/12/12 职场文书
运动会广播稿80字
2014/01/23 职场文书
婚前协议书
2014/04/15 职场文书
水污染治理工程专业自荐信
2014/06/21 职场文书