ES6 Proxy和Object.defineProperty

Object.defindProperty

缺陷:

  1. 无法监听数组变化
  2. 只能劫持对象的属性
var obj = {name: 'name'}

Object.defineProperty(obj, 'name', {
    get: function(){
        return '123';
    }
  
})
obj.name // 123

Proxy

基础用法:

new Proxy(target, handler);

targer 要拦截的对象,handler 拦截行为对象


var obj = new Proxy({}, {
    get: function(){
        return '35';
    }
})

obj.name;// 35
obj.age;// 35

obj2 = {}
obj2.name;// 无
obj2.age;// 无

Proxy针对的是对象实例obj,而不是上面代码中的空对象{}


get(target, propKey[, proxy])

用于拦截某个属性的读取操作,接受三个参数,target为目标对象,propKey为属性名,proxy为实例本身(严格地说,是操作行为所针对的对象),其中最后一个参数可选。

var obj = new Proxy({}, {
    get: function(target, propKey, proxy){
        console.dir(target); // Object
        console.dir(propkey); // name、age
        console.dir(proxy); // Proxy
        if (propKey in target) {
            return target[propKey];
        } else {
            console.log('没有这个属性');
            return null;
        }
    }
})

obj.name = 'new name';

obj.name;// new name
obj.age;// null
var obj = new Proxy({}, {
    get: function(target, propKey, proxy){
        return proxy;
    }
})
console.log(obj.a === obj)// true

set(target, propKey, propValue[, proxy])

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

var obj = new Proxy({}, {
    set: function(target, key, val, proxy){
        console.log(key)
        if (key == 'name') {
            console.log('name 不可修改')
        } else {
            target[key] = val;
        }
        
    }
})

obj.name = 'new name';// undefined
obj.age = '99';// 99

Proxy可以拦截的其他方法:

  • has(target, propKey):拦截propKey in proxy的操作,返回一个布尔值。
  • deleteProperty(target, propKey):拦截delete proxy[propKey]的操作,返回一个布尔值。
  • ownKeys(target):拦截Object.getOwnPropertyNames(proxy)Object.getOwnPropertySymbols(proxy)Object.keys(proxy)for...in循环,返回一个数组。该方法返回目标对象所有自身的属性的属性名,而Object.keys()的返回结果仅包括目标对象自身的可遍历属性。
  • getOwnPropertyDescriptor(target, propKey):拦截Object.getOwnPropertyDescriptor(proxy, propKey),返回属性的描述对象。
  • defineProperty(target, propKey, propDesc):拦截Object.defineProperty(proxy, propKey, propDesc)Object.defineProperties(proxy, propDescs),返回一个布尔值。
  • preventExtensions(target):拦截Object.preventExtensions(proxy),返回一个布尔值。
  • getPrototypeOf(target):拦截Object.getPrototypeOf(proxy),返回一个对象。
  • isExtensible(target):拦截Object.isExtensible(proxy),返回一个布尔值。
  • setPrototypeOf(target, proto):拦截Object.setPrototypeOf(proxy, proto),返回一个布尔值。如果目标对象是函数,那么还有两种额外操作可以拦截。
  • apply(target, object, args):拦截 Proxy 实例作为函数调用的操作,比如proxy(...args)proxy.call(object, ...args)proxy.apply(...)
  • construct(target, args):拦截 Proxy 实例作为构造函数调用的操作,比如new proxy(...args)

Proxy.revocable()

let {proxy, revoke} = Proxy.revocable({}, {});

proxy.foo = 123;
proxy.foo // 123

revoke();
proxy.foo // 报错

console.dir(Proxy.revocable({}, {})); //Object  {proxy, revoke}

 返回一个可以取消的Proxy实例


this问题

在 Proxy 代理的情况下,目标对象内部的this关键字会指向 Proxy 代理。

const target = {
  m: function () {
    console.log(this === proxy);
  }
};
const handler = {};

const proxy = new Proxy(target, handler);

target.m() // false
proxy.m()  // true

const target = new Date();
const handler = {};
const proxy = new Proxy(target, handler);

proxy.getDate();
// TypeError: this is not a Date object.
const target = new Date('2015-01-01');
const handler = {
  get(target, prop) {
    if (prop === 'getDate') {
      return target.getDate.bind(target);
    }
    return Reflect.get(target, prop);
  }
};
const proxy = new Proxy(target, handler);

proxy.getDate() // 1

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值