1. 概述

Proxy 用于修改某些操作的默认行为,等同于在语言层面做出修改,所以属于一种『元编程』即对编程语言进行编程。

1.1 理解

Proxy 是在目标对象之前架设一层『拦截』,外部对对象的访问,都需要经过该层拦截。因此在拦截中对外界的访问进行过滤和改写。

在Es6 中 提供了原生的 Proxy 构造函数,可以用来生成 Proxy实例。

let proxy = new Proxy(target, handler)

Proxy 对象的所有用法,都是上面的形式,不同的只是handler参数的写法。其中new Proxy() 表示生成一个 Proxy实例,target 参数表示所有拦截的目标对象, handler 参数也是一个对象,用来定制拦截行为。如下:

let proxy = new Proxy({}, {
get: function(target, property) {
return 35
}
}) proxy.time // 35
proxy.name // 35
proxy.title // 35

解读:

在上面中,作为构造函数,Proxy接受两个参数。第一个参数即所要代理的目标对象,如果没有 Proxy的介入,操作原来要访问的就是这个对象。第二个参数是一个配置对象,用来对每个代理对象的操作,提供具体的函数和拦截操作。上述代码中有一个 get 函数,用来拦截对目标对象属性的访问请求。

另外,要使 Proxy起作用,必须针对 Proxy 实例进行操作,而不是针对目标对象进行操作。

如果 handler 没有设置任何拦截,那就等同于直接通向原对象。如下:

let target = {}
let handler = {}
let proxy = new Proxy(target, handler) proxy.a = 'b'
target.a = 'b'

对于上面的例子,我们可以讲Proxy对象,设置到 object.proxy属性,从而可以在object对象上调用。

let object = {proxy: new Proxy(target, handler)}

Proxy 实例也可以作为其他对象的原型对象。

let proxy = new Proxy({}, {
get: function(target, property) {
retrun 35
}
}) let obj = Object.create(proxy)
obj.time // 35 另外同一个拦截器,可以设置多个拦截操作。

常用的Proxy支持的拦截操作如下:

  • get(target, propKey, receiver): 拦截对象属性的读取,比如 proxy.foo 和 proxy['foo']
  • set(target, propKey, value, receiver): 拦截对象属性的设置,比如 proxy.foo = v 或 proxy['foo'] = v, 返回一个布尔值
  • has(target, proKey): 拦截propKey in proxy的操作,返回一个布尔值
  • apply(target, object, args): 拦截Proxy 实例作为函数调用的操作,比如 proxy(...args)、proxy.call(object, ...args) 、 proxy.apply(...)。
  • deleteProperty(target, proKey): 拦截 delete proxy[propKey]的操作,返回一个布尔值
  • ownKeys(target): 拦截 Object.getOwnProPertyNames(proxy),返回一个数组。该方法返回目标对象所有自身的属性的属性名,而Object.keys() 的返回结果仅包括目标对象自身的可遍历属性。

1.2 get()

get 方法用于拦截某个属性的读取操作,可以接受三个参数,依次为目标对象、属性名和proxy实例本身,最后一个参数可选。

let p = {
name: '李四'
} let proxy = new Proxy(p, {
get: function(target, property) {
if (property in target) {
retrun target[property]
} else {
console.log('报错')
}
}
}) proxy.name // '李四'
proxy.age // '报错'

注意点

  • get方法可以继承
  • get方法可以进行链式操作

1.3 set

set 方法用来拦截某个属性的赋值操作,可以接受四个参数,依次为目标对象、属性名、属性值和Proxy实例本身,最后一个可选

let v = {
set: function(obj, prop, value) {
if (prop === 'age') {
if(!Number.isInteger(value)) {
console.log('报错')
} if(value > 200) {
console.log('成功')
} obj[prop] = value
}
}
} let p = new Proxy({}, v) p.age = 100 p.age // 100 p.age = 'n'
p.age // 报错

利用set方法,可以数据绑定,即每当对象发生变化时,会自动更新Dom

如果目标对象自身的某个属性,不可写且不可配置,那么Set 方法将不起作用。

1.4 apply()

apply 方法拦截函数的调用、call 和 apply操作。它可以接受三个参数,分别时目标对象、目标对象的上下文对象(this)和目标对象的参数数组。

let h = {
apply(target, ctx, args) {
return Reflect.apply(...arguments)
}
} let target = function() {return 'haha')
let h = {
apply: function() {
return 'heihei'
}
} let p = new Proxy(taraget, h) p() // 'heihei'

1.5 has

has 方法用来拦截 HasProperty 操作, 即判断对象是否具有某个属性时,这个方法会生效。

has 方法可以接受两个参数,分别时目标对象、需要查询的属性名。

注意:has 方法拦截的时 HasProperty操作,而不是HasOwnProperty操作,即has 方法不判断一个属性是对象自身的属性,还是继承的属性。

1.6 construct

construct 方法用于拦截 new命令,下面是拦截对象的写法

let h = {
construct(target, args, newTarget) {
retrun new target(...args)
}
} target: 目标对象
args: 构造函数的参数对象
newTarget: 创造实例对象时,new命令作用的构造函数

1.7 deleteProperty()

deleteProperty 方法用于拦截 delete 操作,如果这个方法抛出错误或者返回false,当前属性就无法被delete命令删除。

2. this问题

虽然 Proxy 可以代理针对目标对象的访问,但它不是目标对象的透明代理,即不做任何拦截的情况下,也无法保证目标对象的行为一致。主要原因就是在Proxy代理的情况下,目标对象内部的this关键字会指向Proxy代理

关注公众号 【小夭同学】

ES6入门之Proxy的更多相关文章

  1. ES6入门笔记

    ES6入门笔记 02 Let&Const.md 增加了块级作用域. 常量 避免了变量提升 03 变量的解构赋值.md var [a, b, c] = [1, 2, 3]; var [[a,d] ...

  2. es6学习笔记-proxy对象

    前提摘要 尤大大的vue3.0即将到来,虽然学不动了,但是还要学的啊,据说vue3.0是基于proxy来进行对值进行拦截并操作,所以es6的proxy也是要学习一下的. 一 什么是proxy Prox ...

  3. es6学习笔记-Proxy、Reflect、Promise

    Proxy Proxy 用于修改某些操作的默认行为,等同于在语言层面做出修改,所以属于一种“元编程”(meta programming),即对编程语言进行编程. Proxy 可以理解成,在目标对象之前 ...

  4. es6入门4--promise详解

    可以说每个前端开发者都无法避免解决异步问题,尤其是当处理了某个异步调用A后,又要紧接着处理其它逻辑,而最直观的做法就是通过回调函数(当然事件派发也可以)处理,比如: 请求A(function (请求响 ...

  5. es6入门3--箭头函数与形参等属性的拓展

    对函数拓展兴趣更大一点,优先看,前面字符串后面再说,那些API居多,会使用能记住部分就好. 一.函数参数可以使用默认值 1.默认值生效条件 在变量的解构赋值就提到了,函数参数可以使用默认值了.正常我们 ...

  6. Vue+koa2开发一款全栈小程序(1.课程介绍+2.ES6入门)

    1.课程介绍 1.课程概述 1.做什么? Vue+koa2开发一款全栈小程序 2.哪些功能? 个人中心.图书列表.图书详情.图书评论.个人评论列表 3.技术栈 小程序.Vue.js.koa2.koa- ...

  7. ES6中的proxy

    1 概述 Proxy 可以理解成,在目标对象之前架设一层“拦截”,外界对该对象的访问,都必须先通过这层拦截,因此提供了一种机制,可以对外界的访问进行过滤和改写. Proxy 这个词的原意是代理,用在这 ...

  8. es6入门5--class类的基本用法

    在ES6之前,准确来说JavaScript语言并无类的概念,却有模拟类的做法.相比在类似java这类传统面向对象语言中通过类来生成实例,js则通过构造函数模拟类来生成实例. 这是因为在JS设计初期,作 ...

  9. 利用ES6中的Proxy和Reflect 实现简单的双向数据绑定

    利用ES6中的Proxy (代理) 和 Reflect 实现一个简单的双向数据绑定demo. 好像vue3也把 obj.defineProperty()  换成了Proxy+Reflect. 话不多说 ...

随机推荐

  1. Android jni/ndk编程二:jni数据类型转换(primitive,String,array)

    一.数据类型映射概述 从我们开始jni编程起,就不可能避开函数的参数与返回值的问题.java语言的数据类型和c/c++有很多不同的地方,所以我们必须考虑当在java层调用c/c++函数时,怎么正确的把 ...

  2. vue类似tab切换的效果,显示和隐藏的判断。

    两者切换,动态显示对应的列表详情. 通过v-show的判断 数据驱动

  3. vue中html、js、vue文件之间的简单引用与关系

    有关vue文件记录:index.html在html中运用组件 <body> <app></app> <!-- 此处app的组件为入口js main.js中定义 ...

  4. Idea Debug多线程不进断点问题处理

    Idea也会使我狼狈不堪,Eclipse下约定成俗,却非Idea的默认规则. 比如 DEBUG多个线程时,Idea的默认设定就会遇到断点不能进入的问题. 解决的方法: 点击DEBUF框下的双红点(Vi ...

  5. DateTime.UtcNow 协调通用时间(UTC)

    1.协调通用时间(UTC) 2.本地时间和UTC时间相互转化 DateTime localDateTime = DateTime.Now;//本地时间 DateTime utcDateTime = D ...

  6. Leetcode之动态规划(DP)专题-62. 不同路径(Unique Paths)

    Leetcode之动态规划(DP)专题-62. 不同路径(Unique Paths) 一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为“Start” ). 机器人每次只能向下或者向 ...

  7. BP原理 - 前向计算与反向传播实例

    Outline 前向计算 反向传播 很多事情不是需要聪明一点,而是需要耐心一点,踏下心来认真看真的很简单的. 假设有这样一个网络层: 第一层是输入层,包含两个神经元i1 i2和截距b1: 第二层是隐含 ...

  8. idea导入eclipse的web项目

    idea导入eclipse的web项目 一.导入自己的web项目      步骤:File->New->Project from Existing Source... 二.选择项目的所在位 ...

  9. [python] 在指定目录下找文件

    import os # 查找当前目录下所有包含关键字的文件 def findFile(path, filekw): return[os.path.join(path,x) for x in os.li ...

  10. sublime text3 注册码 (Version 3.0)

    -– BEGIN LICENSE -– TwitterInc 200 User License EA7E-890007 1D77F72E 390CDD93 4DCBA022 FAF60790 61AA ...