Javascript元编程之Proxy之可代理操作

59 阅读2分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第18天,点击查看活动详情 >>

handler.isExtensible()

在判断代理对象是否可扩展时,将会触发该操作。触发的方式包括有使用Object.isExtensible()以及Reflect.isExtensible()

const monster1 = {
  canEvolve: true
};

const handler1 = {
  isExtensible(target) {
    return Reflect.isExtensible(target);
  },
  preventExtensions(target) {
    target.canEvolve = false;
    return Reflect.preventExtensions(target);
  }
};

const proxy1 = new Proxy(monster1, handler1);

console.log(Object.isExtensible(proxy1));
// expected output: true

console.log(monster1.canEvolve);
// expected output: true

Object.preventExtensions(proxy1);

console.log(Object.isExtensible(proxy1));
// expected output: false

console.log(monster1.canEvolve);
// expected output: false

解释一下上面的代码里关键的部分,首先,preventExtensions是将对象作为参数,把对象设置为不可添加新的属性,他可以删除现有属性,也可以修改现有属性,返回值是原来的对象, 对代理对象的修改会映射在原对象上,代理对象的isExtensible是false,代理对象是不能添加属性的,针对代理对象的修改会同步至原对象

handler.preventExtensions()

在演示是否支持扩展的时候已经涉及了,不再赘述

handler.getOwnPropertyDescriptor()

在获取代理对象的属性描述时,将会触发该操作。触发的方式包括有使用Object.getOwnPropertyDescriptor()以及Reflect.getOwnPropertyDescriptor()

var p = new Proxy({ a: 20}, {
  getOwnPropertyDescriptor: function(target, prop) {
    console.log('called: ' + prop);
    return { configurable: true, enumerable: true, value: target[prop] };
  }
});

console.log(Object.getOwnPropertyDescriptor(p, 'a').value); 

getOwnPropertyDescriptor接受两个参数,target和property,而且,返回的对象必须符合声明对象的对象属性描述符,随意添加的属性是不被解析的,如下图所示

image.png

对象属性描述符

对象属性描述符是由下面的一个或几个组成的,自定义的属性描述符无效

  • value

  • 该属性的值 (仅针对数据属性描述符有效)

  • writable

  • 当且仅当属性的值可以被改变时为 true。(仅针对数据属性描述有效)

  • get

  • 获取该属性的访问器函数(getter)。如果没有访问器,该值为 undefined。(仅针对包含访问器或设置器的属性描述有效)

  • set

  • 获取该属性的设置器函数(setter)。如果没有设置器,该值为 undefined。(仅针对包含访问器或设置器的属性描述有效)

  • configurable

  • 当且仅当指定对象的属性描述可以被改变或者属性可被删除时,为 true。

  • enumerable

  • 当且仅当指定对象的属性可以被枚举出时,为 true

handler.defineProperty()

在定义代理对象的某个属性时,将会触发该操作。触发的方式包括有使用Object.defineProperty()以及Reflect.defineProperty()还有就是直接定义属性名和属性值例如proxy.aa = 5

var p = new Proxy({}, {
  defineProperty: function(target, prop, descriptor) {
    console.log('called: ' + prop);
    return true;
  }
});

var desc = { configurable: true, enumerable: true, value: 10 };
Object.defineProperty(p, 'a', desc); // "called: a"

同样的,defineProperty也只能定义标准的属性描述符,非标准的属性描述符会被忽略,也就是说,我们只能使用上面列出的对象属性描述符来对属性进行定义