美文网首页
Proxy(ES6)深入

Proxy(ES6)深入

作者: Raral | 来源:发表于2020-11-05 08:33 被阅读0次

一 Proxy是什么

  • Proxy 一般是用来架设在目标对象之上的一层拦截,来实现对目标对象访问和修改的控制。Proxy是一个构造函数,使用时必须搭配new操作符,直接调用会报错的。
  • Proxy 构造函数接受两个参数:
    第一个参数: 需要拦截的对象
    第二个参数: 对象和数组或者函数
  • 返回一个新的对象,不是原来的对象

栗子:

    let person = {
        name:"fsd",
        age:23
    }
    let person2 = new Proxy(person,{
        //target: 目标对象person
        //prop: 代理的属性 name
        //receiver: 代理后的对象 person2
        //value: 设置新的值
        get(target,prop,receiver) {
            console.log(target,prop,receiver)
            //{name: "fsd", age: 23} "name Proxy {name: "fsd", age: 23}
            //拦截后可以增强方法
            console.log(`增强方法比如: i am ${prop}`)
            return target[prop]
        },
        set(target,prop,value,receiver) {

        }
    });
    console.log(person,person2);
    console.log(person == person2)//false
    console.log(person2.name)//fsd
  • 13种拦截操作 方法
    [图片上传失败...(image-d5faa5-1604487244374)]
  • get(target, prop, receiver):拦截对象属性的访问。
  • set(target, prop, value, receiver):拦截对象属性的设置,最后返回一个布尔值。
  • apply(target, object, args):用于拦截函数的调用,比如 proxy()。
  • construct(target, args):方法用于拦截 new 操作符,比如 new proxy()。为了使 new操作符在生成的Proxy对象上生效,用于初始化代理的目标对象自身必须具有 [[Construct]] 内部方法(即 new target 必须是有效的)。
  • has(target, prop):拦截例如 prop in proxy的操作,返回一个布尔值。
  • deleteProperty(target, prop):拦截例如 delete proxy[prop] 的操作,返回一个布尔值。
  • ownKeys(target):拦截 Object.getOwnPropertyNames(proxy)、Object.keys(proxy)、for in 循环等等操作,最终会返回一个数组。
  • getOwnPropertyDescriptor(target, prop):拦截 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),返回一个布尔值。如果目标对象是函数,那么还有两种额外操作可以拦截。

二 Proxy和 Object.defineProperty 区别?

在 Proxy对象出现之前,javascript中提供了Object.defineProperty,允许对对象的getter/setter进行拦截,那么两者的区别在哪里?

  1. Object.defineProperty 无法一次性监听对象所有属性,必须遍历或者递归来实现
  2. Object.defineProperty 无法监听到新增加的属性,而Proxy可以增加的属性,因此vue2.x版本需要通过 vm.set(obj,prop,value)这种形式添加。
  3. Object.defineProperty 无法响应式数组操作,可以监听数组的变化(地址),无法监听到对 数组内置的方法(push shift pop unshift) 进行相应。vue2.x通过重写原型方法来实现相应。
  4. Proxy拦截方式多
  5. Object.defineProperty 兼容性比较好,Proxy 支持不了IE全系列

三 Proxy拦截方法的用法

  • 拦截get用法

    get方法接受3个参数
    target: 目标对象;prop:目标属性;receiver:proxy实例(代理对象)

    1. 基于 get 方法的特性,可以实现很多实用的功能,比如在对象里面设置私有属性(一般定义属性我们以 _ 开头表明是私有属性) ,实现禁止访问私有属性的功能。
        const person = {
            name:"tom",
            _sex:"male"//比如私有属性不可访问
        }
        const proxyPerson = new Proxy(person,{
            get(target,prop) {
                if(prop[0] === "_") {
                    throw new Error(`${prop} is private attribute`)
                }
                return target[prop];
            }
        })
        proxyPerson.name // tom
        proxyPerson._sex //Uncaught Error: _sex is private attribute
    
    1. 我们可以给对象中未定义属性设置默认值 undefined
        const defaults = (obj,initValue) => {
            return new Proxy(obj,{
                set(target,prop,receiver) {
                    if(prop in target) {
                        return target[prop]
                    }
                    return initValue
                }
            })
        }
        person = defaults(person,undefined);
        person.name //tom
        console.log(person.age)//undefined
    
  • set用法

    set方法接受3个参数
    target: 目标对象;prop:目标属性;value:属性值; receiver:proxy实例(代理对象)

    1. 表单验证
        // 验证规则  -- 类似设计模式策略模式中 策略集合
        const validators = {
            name: {
                validate(value) {
                    return value.length > 6;
                },
                message: '用户名长度不能小于六'
            },
            password: {
                validate(value) {
                    return value.length > 10;
                },
                message: '密码长度不能小于十'
            },
            moblie: {
                validate(value) {
                    return /^1(3|5|7|8|9)[0-9]{9}$/.test(value);
                },
                message: '手机号格式错误'
            }
        }
        // 验证方法  -- 类似设计模式策略模式中 策略使用
        function validator(obj, validators) {
            return new Proxy(obj, {
                set(target, key, value) {
                    const validator = validators[key]
                    if (!validator) {
                        target[key] = value;
                    } else if (validator.validate(value)) {
                        target[key] = value;
                    } else {
                        alert(validator.message || "");
                    }
                }
            })
        }
        let form = {};
        form = validator(form, validators);
        form.name = '666'; // 用户名长度不能小于六
        form.password = '113123123123123';
    

相关文章

网友评论

      本文标题:Proxy(ES6)深入

      本文链接:https://www.haomeiwen.com/subject/fnkgvktx.html