学习ES6语法proxy之set方法

本文深入探讨了JavaScript中Proxy对象的set方法,通过多个实例展示了如何利用set方法进行属性赋值拦截,包括验证属性值、保护私有属性及利用set方法第四个参数实现特殊功能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

介绍
set方法用来拦截某个属性的赋值操作,可以接受四个参数,
目标对象,属性名,属性值和Proxy实例本身,最后一个参数可选

  • demo1 假定Person对象有个age属性,该属性应该是一个不大于200的整数,那么可以使用Proxy保证age的值符合要求
 {
            let 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');
                    }
                }
                //对于满足条件的age属性以及其他属性,直接保存
                obj[prop] = value;
            }
        };
        let person = new Proxy({},validator);
        person.age = 100;
        console.log(person.age);
        }
  • demo2 有时我们会在对象上面设置内部属性,属性名的第一个字符使用下划线开头,表示这些属性不应该被外部使用。结合get和set方法,就可以做到防止这些内部属性被外部读写。
{
    const handler = {
    get (target,key){
        invariant(key,'get');
        return target[key];
    },
    set (target,key,value){
        invariant(key,'set');
        target[key] = value;
        return true;
    }
};

function invariant (key,action) {
    if(key[0] === '_'){
        throw new Error(`Invalid attempt to ${action} private "${key}"property`)
    }
}

const target = {};
const proxy = new Proxy(target,handler);
}
//console.log("proxy._prop",proxy._prop);
//Invalid attempt to get private "_prop" property at invariant
//proxy._prop = "c";
//Invalid attempt to get private "_prop" property at invariant
  • demo3 下面是set方法第四个参数的例子
{
    const handler = {
        set:function(obj,prop,value,receiver) {
            obj[prop] = receiver;
        }
    };
    const proxy = new Proxy({},handler);
    proxy.foo = 'bar';
    console.log(proxy.foo === proxy);//true
}
//上面的代码中,set方法的第四个参数receiver,指的是原始的操作行为所在的那个对象,一般情况下是proxy实例本身。

  • demo4 请看下面的例子
{
    const handler = {
        set :function (obj,prop,value,receiver) {
            obj[prop] = receiver
        }
    };
    const proxy = new Proxy({},handler);
    const myObj = {};
    Object.setPrototypeOf(myObj,proxy);
    //Object.setPrototypeOf() 方法设置一个指定的对象的原型 ( 即, 内部[[Prototype]]属性)到另一个对象或  null。
    myObj.foo = 'bar';
    console.log(myObj.foo === myObj);//true
}
//上面的代码中设置myObj.foo属性的值时,myObj并没有foo属性,因此引擎会到myObj的原型链上去找foo属性。
//然而,myObj的原型对象proxy是Proxy实例,设置它的foo属性会触发set方法。这时,
//第四个参数receiver就指向原始赋值行为所在的对象myObj

//注意:如果目标对象自身的某个属性,不可写且不可配置,那么set方法将不起作用。
  • demo5
{
    const obj = {};
    Object.defineProperty(obj,'foo',{
        value:'bar',
        writable:false,
    });
    const handler = {
        set :function (obj,prop,value,receiver) {
            obj[prop] = 'baz';
        }
    };
    const proxy = new Proxy(obj,handler);
    proxy.foo = 'baz';
    console.log("proxy.foo",proxy.foo);//proxy.foo bar
}
//上面代码中,obj.foo属性不可写,Proxy 对这个属性的set代理将不会生效  writable属性控制是否可写。

  • demo6 注意,严格模式下,set代理如果没有返回true,就会报错
{
    'use strict';
    const handler ={
        set:function (obj,prop,value,receiver) {
            obj[prop] = value;
            //无论有没有下面这一行,都会报错
            //return true;

        }
    }
    const proxy = new Proxy({},handler);
    proxy.foo='bar';
    console.log("proxy.foo",proxy.foo=='bar');
}

//上面这个实例有没有renturn似乎并没有什么关系,此实例摘自阮一峰ECMAScript6 入门Proxy set方法最后一个实例

例子来源于阮一峰的es6入门,如果哪里写的不完整欢迎指正,还是萌新还望包容!

### ES6Proxy 对象的核心特性与使用方法 #### 1. **Proxy 的基本概念** `Proxy` 是 ECMAScript 6ES6)引入的一种新功能,用于拦截并重新定义对象的基本操作行为。它允许开发者在访问或修改目标对象时插入自定义逻辑[^1]。 --- #### 2. **核心组成部分** `Proxy` 主要由两部分组成: - **目标对象 (`target`):** 被代理的对象。 - **处理器 (`handler`):** 定义了一系列陷阱函数(trap functions),用来捕获对目标对象的操作。 以下是 `Proxy` 构造器的标准语法: ```javascript const proxy = new Proxy(target, handler); ``` 其中,`target` 可以是一个普通的对象、数组甚至函数;而 `handler` 则包含了各种可选的方法来拦截不同的操作。 --- #### 3. **常见的陷阱函数及其用途** ##### (1)数据验证——`set` 方法 当尝试设置某个属性的值时,可以通过 `set` 来执行额外的数据校验逻辑。例如: ```javascript let validator = { set: function (obj, prop, value) { if (prop === 'age') { if (!Number.isInteger(value)) { throw new Error('The age must be an integer'); } if (value > 200 || value < 0) { throw new Error('The age seems invalid'); } } obj[prop] = value; return true; } }; let person = new Proxy({}, validator); person.age = 18; // 正常赋值 console.log(person.age); // 输出 18 try { person.age = 'young'; // 抛出错误 } catch (e) { console.error(e.message); // The age must be an integer } ``` 上述代码展示了如何通过 `set` 实现简单的年龄字段校验。 --- ##### (2)读取控制——`get` 方法 可以利用 `get` 拦截对属性的读取请求,并返回经过加工后的结果。比如隐藏敏感信息或者提供默认值: ```javascript let user = { firstName: 'John', lastName: 'Doe' }; let handlerGet = { get: function (target, key) { if (!(key in target)) { return `${key} is not defined`; } return target[key]; } }; let proxiedUser = new Proxy(user, handlerGet); console.log(proxiedUser.firstName); // John console.log(proxiedUser.email); // email is not defined ``` 此示例说明了如何优雅地处理未定义键的情况[^4]。 --- ##### (3)实例化支持——`construct` 和 `apply` 如果目标本身是个构造函数,则可通过 `construct` 或者对于普通函数调用则借助于 `apply` 进行扩展管理[^3]。下面展示了一个例子,演示如何记录每次类实例化的次数: ```javascript function MyClass() {} MyClass.prototype.incrementCount = function () {}; let countHandler = { construct: function (target, args, newTarget) { const instance = Reflect.construct(...arguments); Object.defineProperty(instance, '_count', { writable: true }); instance._count++; return instance; }, }; let CountableClass = new Proxy(MyClass, countHandler); let a = new CountableClass(); a._count++; // 修改计数器变量 console.log(a._count); // 结果为 1 ``` 这里我们看到即使是在复杂场景下也能灵活运用 Proxies 提供的功能。 --- #### 4. **实际应用案例分析** 为了更直观理解其强大之处,在日常开发过程中经常遇到的需求之一就是实时监控某些特定状态的变化情况。这正是前面提到过的关于工程师信息更新的通知机制: ```javascript var engineer = { name: 'Alice', skills: ['JavaScript'] }; var interceptor = { set: function (receiver, property, value) { console.log(`${property} was updated from ${receiver[property]} to ${value}`); receiver[property] = value; } }; new Proxy(engineer, interceptor).skills.push('Python'); // Output: // skills was updated from ["JavaScript"] to ["JavaScript", "Python"] ``` 这段脚本清楚表明每当技能列表发生变化都会打印相应的日志消息出来。 --- ### 总结 综上所述,`Proxy` 不仅赋予了 JavaScript 更加丰富的元编程能力,还极大地增强了应用程序灵活性和可控度。无论是基础的数据验证还是高级别的框架设计都可以找到它的身影[^2]。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值