卖坚果的怪叔叔 卖坚果的怪叔叔
  • 首页
  • 生活
  • 技术
  • 记录
  • 工具箱
  • 关于我
首页 › 技术 › ES6入门之Proxy

ES6入门之Proxy

坚果大叔
2019-09-06 11:16:14技术阅读 2,987

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命令删除。

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

Es6 proxy
赞赏 赞(0)
本文系作者 @坚果大叔 原创发布在 卖坚果的怪叔叔。未经许可,禁止转载。
重学Javascript之引用类型
上一篇
前端两三问
下一篇
在小程序中查看

这是个😊,挣点服务器费用😜

热门文章
deep 不生效!
一键解决VsCode官网下载慢的问题
将数组中空值字段赋默认值!
看一看
国庆假期的一些照片~
Mac更换node版本切换工具n模块的镜像源
专题标签
agent (1) CSS (15) dom (1) Es6入门系列 (14) Git (3) html (1) iview (1) JavaScript (9) js (4) Lif (1) Node (4) pyecharts (1) Python (10) ref (1) scriptable (1) Skill (1) vsCode (1) vue (4) wordpress (2) 三月 (1) 上海 (1) 假期 (1) 其他分享 (3) 前端两三问 (15) 古镇 (1) 外滩 (1) 对象 (1) 小程序 (5) 年度总结 (6) 年终总结 (1) 微信机器人 (4) 打字机 (1) 技术 (1) 日常问题 (8) 日常问题记录 (1) 春天 (2) 服务器 (2) 海族馆 (1) 生活 (8) 网上国网 (1) 记录 (3) 通勤 (1) 重学JavaScript (11) 面试题 (10) 🌸 (1)
什么是Agent?
2026-08-15 23:49:12
407 0 2
什么是 Skill?
2026-08-12 21:32:42
322 1 0
失业在家,我给小朋友做了一个练字小程序!
2026-08-07 16:21:52
603 10 1
上线8年,15万用户的小程序,一共赚了多少钱?
2026-05-30 18:01:24
4,651 4 0
  • 0
博主

一位佛系的前端开发者,略通摄影,乐于尝试新事物,热衷于美食。

友链
故事胶片
公众号
坚果大叔 执行上下文 卖坚果的怪叔叔 Dacking
Copyright © 2017-2026 卖坚果的怪叔叔

开往-友链接力

萌ICP备20230818号

苏ICP备18048410号-3
  • 首页
  • 生活
  • 技术
  • 记录
  • 工具箱
  • 关于我
# CSS # # JavaScript # # vue # # 微信 # # 生活 #
坚果大叔
345
文章
171
评论
432
喜欢