Skip to content

es6之Proxy以及类型判断

类型判断: How to check the type of es6 proxy in Javascript? - Stack Overflow

Proxy - JavaScript | MDN

Proxy 对象用于创建一个对象的代理,从而实现基本操作的拦截和自定义(如属性查找、赋值、枚举、函数调用等)。

额外知识 getOwnPropertyDescriptor

Object.getOwnPropertyDescriptor() - JavaScript | MDN
Object.getOwnPropertyDescriptor() 方法返回指定对象上一个自有属性对应的属性描述符。(自有属性指的是直接赋予该对象的属性,不需要从原型链上进行查找的属性)

js
const object1 = {
  property1: 42
};

const descriptor1 = Object.getOwnPropertyDescriptor(object1, 'property1');

console.log(descriptor1.configurable);
// expected output: true

console.log(descriptor1.value);
// expected output: 42
const object1 = {
  property1: 42
};

const descriptor1 = Object.getOwnPropertyDescriptor(object1, 'property1');

console.log(descriptor1.configurable);
// expected output: true

console.log(descriptor1.value);
// expected output: 42
js
var o = { get foo() { return 17; } };
d = Object.getOwnPropertyDescriptor(o, "foo");
/*
结果:
{
	set: undefined, 
	enumerable: true,  // 当且仅当指定对象的属性可以被枚举出时,为 `true`。
	configurable: true //当且仅当指定对象的属性描述可以被改变或者属性可被删除时,为 `true`, 
	get: ƒ             //获取该属性的访问器函数(getter)。如果没有访问器,该值为 undefined。(仅针对包含访问器或设置器的属性描述有效)
}
*/
d = Object.getOwnPropertyDescriptor(o, "bar");
/*
{
	value: 17, //该属性的值 (仅针对数据属性描述符有效)
	writable: true, //当且仅当属性的值可以被改变时为 `true`。(仅针对数据属性描述有效)
	enumerable: true, 
	configurable: true
}
*/
var o = { get foo() { return 17; } };
d = Object.getOwnPropertyDescriptor(o, "foo");
/*
结果:
{
	set: undefined, 
	enumerable: true,  // 当且仅当指定对象的属性可以被枚举出时,为 `true`。
	configurable: true //当且仅当指定对象的属性描述可以被改变或者属性可被删除时,为 `true`, 
	get: ƒ             //获取该属性的访问器函数(getter)。如果没有访问器,该值为 undefined。(仅针对包含访问器或设置器的属性描述有效)
}
*/
d = Object.getOwnPropertyDescriptor(o, "bar");
/*
{
	value: 17, //该属性的值 (仅针对数据属性描述符有效)
	writable: true, //当且仅当属性的值可以被改变时为 `true`。(仅针对数据属性描述有效)
	enumerable: true, 
	configurable: true
}
*/

Proxy

Proxy 对象用于创建一个对象的代理,从而实现基本操作的拦截和自定义(如属性查找、赋值、枚举、函数调用等)。

js
const p = new Proxy(target, handler)
const p = new Proxy(target, handler)
  • target:要使用 Proxy 包装的目标对象(可以是任何类型的对象,包括原生数组,函数,甚至另一个代理)。
  • handler:一个通常以函数作为属性的对象,各属性中的函数分别定义了在执行各种操作时代理 p 的行为。

举例1

js
const handler = {  
  get: function (obj, prop) {  
    console.log('get calling:', obj, prop)  
    return prop in obj ? obj[prop] : 37;  
  }  
};

const originData = {}  
const p = new Proxy(/*target*/originData, /*handler*/handler);  
p.a = 1;  
p.b = undefined;  
  
console.log(p.a, p.b);      // 1, undefined  
console.log('c' in p, p.c); // false, 37  
console.log('originData', originData) // 原始数据也会被赋值
const handler = {  
  get: function (obj, prop) {  
    console.log('get calling:', obj, prop)  
    return prop in obj ? obj[prop] : 37;  
  }  
};

const originData = {}  
const p = new Proxy(/*target*/originData, /*handler*/handler);  
p.a = 1;  
p.b = undefined;  
  
console.log(p.a, p.b);      // 1, undefined  
console.log('c' in p, p.c); // false, 37  
console.log('originData', originData) // 原始数据也会被赋值

举例2 校验

js
const validator = {  
  set: function (obj, prop, value) {  
    if (prop === 'age') {  
      if (!Number.isInteger(value)) {  
        throw new TypeError('The age is not an integer');  
      }  
      if (value > 200) {  
        throw new RangeError('The age seems invalid');  
      }  
    }  
    // The default behavior to store the value  
    obj[prop] = value;  
    // 表示成功  
    return true;  
  }  
};  
  
let person = new Proxy({}, validator);  
person.age = 100;  
console.log(person.age);  
// 100  
try {  
  person.age = 'young';  
} catch (e) {  
  // 抛出异常:Uncaught TypeError: The age is not an integer  
  console.error(e)  
}  
try {  
  person.age = 300;  
} catch (e) {  
  // 抛出异常:Uncaught RangeError: The age seems invalid  
  console.error(e)  
}  
// 方法代理可以轻松地通过一个新构造函数来扩展一个已有的构造函数。这个例子使用了construct和apply。
const validator = {  
  set: function (obj, prop, value) {  
    if (prop === 'age') {  
      if (!Number.isInteger(value)) {  
        throw new TypeError('The age is not an integer');  
      }  
      if (value > 200) {  
        throw new RangeError('The age seems invalid');  
      }  
    }  
    // The default behavior to store the value  
    obj[prop] = value;  
    // 表示成功  
    return true;  
  }  
};  
  
let person = new Proxy({}, validator);  
person.age = 100;  
console.log(person.age);  
// 100  
try {  
  person.age = 'young';  
} catch (e) {  
  // 抛出异常:Uncaught TypeError: The age is not an integer  
  console.error(e)  
}  
try {  
  person.age = 300;  
} catch (e) {  
  // 抛出异常:Uncaught RangeError: The age seems invalid  
  console.error(e)  
}  
// 方法代理可以轻松地通过一个新构造函数来扩展一个已有的构造函数。这个例子使用了construct和apply。