返回

深入理解 ES6 Proxy 实例方法,掌握对象操作的精髓

前端

ES6 Proxy 实例方法概述

ES6 Proxy 实例方法为 JavaScript 提供了强大的对象操作能力,它允许你截获和修改对象的各种操作,从而实现对象的自定义行为。

Proxy 实例方法主要包括以下几种:

  • get:当读取某个属性时触发。
  • set:当写入某个属性时触发。
  • has:当使用 in 操作符检查属性是否存在时触发。
  • deleteProperty:当使用 delete 操作符删除属性时触发。
  • getPrototypeOf:当使用 Object.getPrototypeOf() 获取对象的原型时触发。
  • setPrototypeOf:当使用 Object.setPrototypeOf() 设置对象的原型时触发。
  • preventExtensions:当使用 Object.preventExtensions() 尝试阻止对象添加新属性时触发。
  • isExtensible:当使用 Object.isExtensible() 检查对象是否可扩展时触发。
  • ownKeys:当使用 Object.getOwnPropertyNames()、Object.getOwnPropertySymbols() 或 for...in 循环枚举对象的自身属性时触发。
  • apply:当使用 Function.prototype.apply() 调用函数时触发。
  • construct:当使用 new 运算符创建对象时触发。

ES6 Proxy 实例方法详解

get

get 方法在读取某个属性时触发。它接收三个参数:

  • target:目标对象。
  • property:要读取的属性名。
  • receiver:调用 get 方法的代理对象。

get 方法可以返回任意值,包括原始值、对象、函数等。如果 get 方法返回 undefined,则会引发 TypeError 异常。

set

set 方法在写入某个属性时触发。它接收四个参数:

  • target:目标对象。
  • property:要写入的属性名。
  • value:要写入的属性值。
  • receiver:调用 set 方法的代理对象。

set 方法必须返回一个布尔值,表示写入操作是否成功。如果 set 方法返回 false,则会引发 TypeError 异常。

has

has 方法在使用 in 操作符检查属性是否存在时触发。它接收两个参数:

  • target:目标对象。
  • property:要检查的属性名。

has 方法必须返回一个布尔值,表示属性是否存在。如果 has 方法返回 false,则 in 操作符会返回 false。

deleteProperty

deleteProperty 方法在使用 delete 操作符删除属性时触发。它接收两个参数:

  • target:目标对象。
  • property:要删除的属性名。

deleteProperty 方法必须返回一个布尔值,表示删除操作是否成功。如果 deleteProperty 方法返回 false,则会引发 TypeError 异常。

getPrototypeOf

getPrototypeOf 方法在使用 Object.getPrototypeOf() 获取对象的原型时触发。它接收一个参数:

  • target:目标对象。

getPrototypeOf 方法必须返回一个对象,表示对象的原型。如果 getPrototypeOf 方法返回 null,则会引发 TypeError 异常。

setPrototypeOf

setPrototypeOf 方法在使用 Object.setPrototypeOf() 设置对象的原型时触发。它接收两个参数:

  • target:目标对象。
  • prototype:要设置的原型对象。

setPrototypeOf 方法必须返回一个布尔值,表示设置操作是否成功。如果 setPrototypeOf 方法返回 false,则会引发 TypeError 异常。

preventExtensions

preventExtensions 方法在使用 Object.preventExtensions() 尝试阻止对象添加新属性时触发。它接收一个参数:

  • target:目标对象。

preventExtensions 方法必须返回一个布尔值,表示阻止操作是否成功。如果 preventExtensions 方法返回 false,则会引发 TypeError 异常。

isExtensible

isExtensible 方法在使用 Object.isExtensible() 检查对象是否可扩展时触发。它接收一个参数:

  • target:目标对象。

isExtensible 方法必须返回一个布尔值,表示对象是否可扩展。如果 isExtensible 方法返回 false,则对象不可扩展。

ownKeys

ownKeys 方法在使用 Object.getOwnPropertyNames()、Object.getOwnPropertySymbols() 或 for...in 循环枚举对象的自身属性时触发。它接收一个参数:

  • target:目标对象。

ownKeys 方法必须返回一个数组,包含对象的所有自身属性名。

apply

apply 方法在使用 Function.prototype.apply() 调用函数时触发。它接收三个参数:

  • target:目标函数。
  • thisArg:函数的 this 值。
  • args:函数的参数数组。

apply 方法必须返回一个值,表示函数的返回值。

construct

construct 方法在使用 new 运算符创建对象时触发。它接收三个参数:

  • target:目标类。
  • args:构造函数的参数数组。
  • newTarget:new 运算符的目标函数。

construct 方法必须返回一个对象,表示创建的对象。

ES6 Proxy 实例方法示例

使用 get 方法拦截属性读取

const target = {
  name: '张三',
  age: 20
};

const proxy = new Proxy(target, {
  get: function(target, property) {
    console.log(`读取属性:${property}`);
    return target[property];
  }
});

console.log(proxy.name); // 读取属性:name
console.log(proxy.age); // 读取属性:age

使用 set 方法拦截属性写入

const target = {};

const proxy = new Proxy(target, {
  set: function(target, property, value) {
    console.log(`写入属性:${property},值为:${value}`);
    target[property] = value;
  }
});

proxy.name = '张三'; // 写入属性:name,值为:张三
proxy.age = 20; // 写入属性:age,值为:20

使用 has 方法拦截属性检查

const target = {
  name: '张三'
};

const proxy = new Proxy(target, {
  has: function(target, property) {
    console.log(`检查属性:${property}`);
    return target.hasOwnProperty(property);
  }
});

console.log('name' in proxy); // 检查属性:name
console.log('age' in proxy); // 检查属性:age

使用 deleteProperty 方法拦截属性删除

const target = {
  name: '张三'
};

const proxy = new Proxy(target, {
  deleteProperty: function(target, property) {
    console.log(`删除属性:${property}`);
    delete target[property];
  }
});

delete proxy.name; // 删除属性:name

使用 getPrototypeOf 方法拦截原型获取

const target = {
  name: '张三'
};

const proxy = new Proxy(target, {
  getPrototypeOf: function(target) {
    console.log('获取原型');
    return Object.getPrototypeOf(target);
  }
});

console.log(Object.getPrototypeOf(proxy)); // 获取原型

使用 setPrototypeOf 方法拦截原型设置

const target = {};

const proxy = new Proxy(target, {
  setPrototypeOf: function(target, prototype) {
    console.log(`设置原型:${prototype}`);
    Object.setPrototypeOf(target, prototype);
  }
});

Object.setPrototypeOf(proxy, Array.prototype); // 设置原型:Array.prototype

使用 preventExtensions 方法拦截对象扩展

const target = {};

const proxy = new Proxy(target, {
  preventExtensions: function(target) {
    console.log('阻止对象扩展');
    Object.preventExtensions(target);
  }
});

Object.preventExtensions(proxy); // 阻止对象扩展

使用 isExtensible 方法检查对象是否可扩展

const target = {};

const proxy = new Proxy(target, {
  isExtensible: function(target) {
    console.log('检查对象是否可扩展');
    return Object.isExtensible(target);
  }
});

console.log(Object.isExtensible(proxy)); // 检查对象是否可扩展

使用 ownKeys 方法拦截属性枚举

const target = {
  name: '张三',
  age: 20
};

const proxy = new Proxy(target, {
  ownKeys: function(target) {
    console.log('枚举属性');
    return Object.getOwnPropertyNames(target);
  }
});

for (const property of Object.keys(proxy)) {
  console.log(property); // 枚举属性
}

使用 apply 方法拦截函数调用

const target = function() {
  console.log('函数调用');
};

const proxy = new Proxy(target, {
  apply