proxy
发布于 4 年前 作者 ming34 1677 次浏览 来自 分享

Proxy

概述

ES6提供原生Proxy构造函数,用来生成proxy实例

let proxy = new Proxy(target , handler)

上面 target表示要拦截的对象 , handler用来定制拦截行为

拦截读取属性的例子

let proxy = new Proxy({} , {
    get: function(target , propKey){
        console.log(target); // {}
        console.log(propKey); // 
        return 33
    }
})
console.log(proxy.title) // 33
console.log(proxy.name) // 33

Proxy支持的拦截操作

get()

get(target , propKey , receiver)
用于拦截某个属性的读取操作
接受三个参数,目标对象 , 属性名 , 可选的 proxy实例本身(严格来说是操作行为所针对的对象)

let person = {
    name: '张三'
}
let proxy = new Proxy(person , {
    get: function(target , propKey , receiver){
        console.log(target , propKey , receiver);
        if(propKey in person){
            return person[propKey]
        } else {
            throw new ReferenceError(propKey +  " is no found")
        }
    }
})
console.log(proxy.name)
console.log(proxy.title)

set

用来拦截某个属性的赋值操作

接受四个参数: 目标对象 属性名 属性值 proxy对象

拦截表单输入,表单验证抛出错误

<style>
    .input{
        width: 100px;
        height: 20px;
    }
    .border{
        border: 1px solid black;
    }
    .red-border{
        border: 1px solid red;
    }
</style>
<input type="text" class="input border" placeholder="年龄" oninput="inputAge(this.value)">
// 拦截的行为
let validator = {
    set: function(target , porpKey , value , reveiver){
        if(porpKey == 'age'){
            // 大于20 异常
            assert(value > 20 , 'more 20');
            // 小于10 异常
            assert(value < 10 , 'less 10');
        }
        target[porpKey] = value;
    },
    get: function(target , porpKey , receiver){
        return target[porpKey];
    }
}
let data = new Proxy({} , validator);
// 防抖
let throttle = {
    wait: 1000 , 
    timeoutId: null ,
    process: function(func , ...nums){
        if(typeof func == 'function'){
            clearTimeout(this.timeoutId);
            this.timeoutId = setTimeout(()=>{
                func(...nums)
            } , this.wait)
        }
    }
}
function inputAge(val){
    let age = Number(val);
    throttle.process(validAge , age)
}
let ageInput = document.querySelector("#ageInput")
function validAge(age){
    try {
        data.age = age;
        console.log(data.age)
        ageInput.classList.add("border")
        ageInput.classList.remove("red-border")
    } catch (error) {
        // 异常的情况下边框要变红
        ageInput.classList.remove("border")
        ageInput.classList.add("red-border")
        console.log(error.message)                
    }
}
// 自定义的抛异常的函数
function assert(condition , msg){
    if(condition){
        throw new Error(msg)
    }
}

有时我们会定义一些内部属性,通常用 _name 这种形式 , 表示这些属性不应该被外部使用。

// 拦截的行为
let handler = {
    get: function(target , propKey , proxy){
        invariant(propKey , 'get');
        return target[propKey]
    },
    set: function(target , propKey , value , proxy){
        invariant(propKey , 'set');
        target[propKey] = value
    }
}
function invariant(key , action){
    if(key[0] === '_'){
        throw new Error( key + '' + action + '')
    }
}
let proxy = new Proxy({} , handler);
proxy.name = 'www';
console.log(proxy.name);
proxy._name = '_nn';
console.log(proxy._name); //error

set方法的第四个参数

// 拦截的行为
let handler = {
    set: function(target , propKey , value , proxy){
        target[propKey] = proxy
    }
}
let proxy = new Proxy({} , handler);
proxy.foo = 'xxx';
console.log(proxy.foo === proxy) // true

严格模式下,set不返回true的话就会报错

has

deleteProperty

待续。。。。

2 回复

你忘记添加 ageInput 这个id 了

还是不太了解使用场景

回到顶部