4

Proxy代理数据拦截方法

 1 year ago
source link: https://www.fly63.com/article/detial/12246
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

proxy

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

new Proxy(target,handler)

// target 是proxy 要包装的对象 (可以是数组、函数,也可以是另一个Proxy)
//handler 一个通常以函数作为属性的对象,用来定制拦截行为

基本的语法是:

const p = new Proxy(target,handler)

主要的方法有:
handler.has() 是针对 in 操作符的代理方法
handler.set() 方法是设置属性值操作的捕获器。
handler.get() 方法用于拦截对象的读取属性操作。
handler.defineProperty() 用于拦截对对象的 Object.defineProperty() 操作。
handler.deleteProperty() 方法用于拦截对对象属性的 delete 操作。

handler.has()方法

const obj = {
    name: '微芒不朽',
    occupation: '前端开发'
}

const handler = {
    has(target, key) {
        //判断是否存在该属性
        return key in target
    }
}


const p = new Proxy(obj, handler)
console.log(p.name) //微芒不朽
console.log(p.like) //undefined
console.log(p.occupation) //前端开发

handler.get()方法

const obj = {
    name: '微芒不朽',
    occupation: '前端开发'
}

const handler = {
    has(target, key) {
        //判断是否存在该属性
        return key in target
    },
    get(target, key) {
        if (key in target) {
            return target[key]
        } else {
            return new ReferenceError(key + '属性不存在')
        }
    }
}

const p = new Proxy(obj, handler)
console.log(p.name) //微芒不朽
console.log(p.like) //ReferenceError: like属性不存在
console.log(p.occupation) //前端开发

handler.set()方法

const obj = {
    name: '微芒不朽',
    occupation: '前端开发'
}

const handler = {
    set(target, key) {
        if (key in target) {
            return Reflect.set(...arguments)
        }
        throw new ReferenceError(key+'属性不存在')
    }
}

const p = new Proxy(obj, handler)
p.like = '编程' //Uncaught ReferenceError: like属性不存在
// console.log(p.like)
p.occupation = '测试'
console.log(p.occupation) //测试

handler.defineProperty() 方法

用于拦截对对象的 Object.defineProperty() 操作

const obj = {
    name: '微芒不朽',
    configurable: true,
    enumerable: true,
}

const handler = {
    defineProperty(target, key, descriptor) {
        console.log('属性', key)
        return true;
    }
}

const p = new Proxy({}, handler)
Object.defineProperty(p, 'like', obj) //属性 like

也可以使用 Reflect.defineProperty

const obj = {
    name: '微芒不朽',
    configurable: true,
    enumerable: true,
}

const handler1 = {
    defineProperty(target, key, descriptor) {
        console.log('属性1', descriptor)
        return Reflect.defineProperty(target, key, descriptor)
    }
}

const p1 = new Proxy({}, handler)
Object.defineProperty(p1, 'like', obj) //属性 like

handler.deleteProperty() 方法

主要拦截对象的 delete操作;

const obj = {
    name: '微芒不朽',
}

const handler = {
    deleteProperty(target, key) {
        console.log('删除' + key)
    }
}

const p = new Proxy({}, handler)
delete p.name //删除name

//也会拦截 Reflect.deleteProperty
Reflect.deleteProperty(obj,'name')

Proxy.revocable 撤销代理

proxy有一个唯一的静态方法,Proxy.revocable(target, handler)

Proxy.revocable()方法可以用来创建一个可撤销的代理对象。 该方法的返回值是一个对象,其结构为: {"proxy": proxy, "revoke": revoke}

  • proxy 表示新生成的代理对象本身,和用一般方式 new Proxy(target, handler) 创建的代理对象没什么不同,只是它可以被撤销掉。
  • revoke 撤销方法,调用的时候不需要加任何参数,就可以撤销掉和它一起生成的那个代理对象。
const obj = {
    name: '微芒不朽',
}
const handler = {}
const { proxy, revoke } = Proxy.revocable(obj, handler)
console.log(proxy.name) //微芒不朽
revoke() // 取值完成对proxy进行封闭,撤消代理
console.log(proxy.name) // Uncaught TypeError: illegal operation attempted on a revoked proxy

Proxy实现一个格式检验器

场景:验证身份证、电话、姓名和邮箱

const obj = {
    certno: '420101198101012964',
    name: '微芒不朽1',
    tel: '123456789',
    mail: '[email protected]',
}

const validators = {
    //校验证件号码
    certno(val) {
        return /(^\d{15}$)|(^\d{18}$)|(^\d{17}(\d|X|x)$)/.test(val)
    },
    //校验姓名,只能为汉字
    name(val) {
        return /^[\u0391-\uFFE5]+$/.test(val)
    },
    //检验电话或手机号
    tel(val) {
        return /^1\d{10}$|^0\d{2,3}-?\d{7,8}$/.test(val)
    },
    //检验邮箱
    mail() {
        return /^[a-zA-Z0-9_.-]+@[a-zA-Z0-9-]+(\.[a-zA-Z0-9-]+)*\.[a-zA-Z0-9]{2,6}$/.test(val)
    }
}

const validatorType = (target, validator) => {
   return new Proxy(target, {
        _validator: validator,
        set(target, key, value, proxy) {
            let validator = this._validator[key](value)
            if (validator) {
                return Reflect.set(target, key, value, proxy)
            } else {
                throw Error(`设置${key} 的值为 ${value},格式不正确`)
            }
        }
    })
}

const proxy = validatorType(obj, validators)
proxy.certno = '420101198101012964'
proxy.name = '微芒不朽1' //Uncaught Error: 设置name 的值为 微芒不朽1,格式不正确
proxy.tel = '123456789' //Uncaught Error: 设置tel 的值为 123456789,格式不正确
proxy.mail = '[email protected]'

proxy 拦截私有属性

用proxy拦截日常定义的私有属性,使其不能更改;一般以下划线开头;

let obj = {
    _id:'1234567890',
    name:'微芒不朽'
}
const p = new Proxy(obj,{
    set(target,prop){
        if(prop[0]==='_'){
            throw Error( `${prop}为私有属性`)
        }
        return Reflect.set(target,prop)
    }
})

p.name = '加油啊'
console.log(p.name) //加油啊
p._id = '123'
console.log(p._id) //Uncaught Error: _id为私有属性

reactive函数

用来绑定引用数据类型, 例如对象和数组等,实现响应式。 Proxy 本质上是对某个对象的劫持,这样它不仅仅可以监听对象某个属性值的变化,还可以监听对象属性的新增和删除 。而 reactive 是 vue3 中对数据进行劫持的核心 。

//判断是否为对象
function isObject(value) {
return value != null && (typeof value === 'object' || typeof value === 'function')
}

function reactive(obj) {
if (!isObject(obj)) {
return obj
}
return new Proxy(obj, {
get(target, key) {
// TODO:收集依赖
return Reflect.get(target, key)
},
set(target, key, value) {
// TODO:触发依赖
return Reflect.set(target, key, value)
}
})
}
const state = reactive({
name: '微芒不朽'
})
console.log(state) //Proxy代理的对象
// Proxy { <target>: {…}, <handler>: {…} }
// <target>: Object { name: "微芒不朽" }
// name: "微芒不朽"
// <prototype>: Object { … }
// <handler>: Object { get: get(target, key), set: set(target, key, value)
// }
// get: function get(target, key)
// set: function set(target, key, value)

来自:https://segmentfault.com/a/1190000042949615

链接: https://www.fly63.com/article/detial/12246


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK