当前位置:   article > 正文

ES6的Proxy的理解与运用_es6中proxy的target是函数

es6中proxy的target是函数

Proxy的定义和语法

proxy的理解

首先proxy的英文意思的代理,proxy用自己的话理解的话就是一个拦截器或者是过滤器

感觉本质上就是在被代理的目标对象上加了一些事件行为

语法

const p = new Proxy(target, handler)

参数

  • 要使用 Proxy 包装的目标对象(可以是任何类型的对象,包括原生数组,函数,甚至另一个代理)。
  • 一个通常以函数作为属性的对象,各属性中的函数分别定义了在执行各种操作时代理 p 的行为。

let obj = {
    a:5
}

const proxyObj = new Proxy(obj,{
    get:function(){
        return  'proxy'
    },
    set:function(){
       
    }
})
console.log(obj.a);
console.log(proxyObj.a);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

上述
Proxy 实例也可以作为其他对象的原型对象。

const proxyObj = new Proxy(obj,{
    get:function(target,attr){
        return  target[attr]
    },
    set:function(){
       
    }
})
console.log(obj.a);
console.log(proxyObj.a);

// class Ctx1{

// }

function Ctx(){

}

console.log(Ctx.prototype,Ctx1.prototype);


Ctx.prototype = Object.create(proxyObj)
let x = new Ctx()
console.log(x.a);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25

在这里插入图片描述

Proxy的handler对象上的方法

get(target, propKey, receiver):

handler.get() 方法用于拦截对象的读取属性操作。

语法

var p = new Proxy(target, {
  get: function(target, property, receiver) {
  }
});
  • 1
  • 2
  • 3
  • 4
  • target 目标对象。
  • property 被获取的属性名。
  • receiver Proxy或者继承Proxy的对象 返回值

get方法可以返回任何值。

拦截
该方法会拦截目标对象的以下操作:

  1. 访问属性: proxy[foo]和 proxy.bar
  2. 访问原型链上的属性: Object.create(proxy)[foo]
  3. Reflect.get()
const obj = {
    attr:'property',
    void:'method'
}


const proxyObj = new Proxy(obj,{
    get:function(target,prop){
        if(prop in target){
            // 有这个属性就返回
            return target[prop]
        }else{
            // 没有这个属性就报错
            console.log(target);
            throw  ReferenceError(`${prop} is not exsit in target object`)
        }
    }
})

console.log(proxyObj.attr );
console.log(proxyObj.void);
console.log(proxyObj.a);

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

在这里插入图片描述

get的第三个对象
第三个对象就是返回当前调用的proxy实例


const proxy = new Proxy({},{
    get(target,prop,receiver){
        return receiver
    }
})

 
console.log(proxy.getReceiver === proxy);//true
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

set(target, property, value, receiver)

andler.set() 方法是设置属性值操作的捕获器。

语法
const p = new Proxy(target, {
  set: function(target, property, value, receiver) {
  }
});
  • 1
  • 2
  • 3
  • 4
  • 5

以下是传递给 set() 方法的参数。this 绑定在 handler 对象上。

  • target 目标对象。
  • property 将被设置的属性名或 Symbol。
  • value 新属性值。
  • receiver
    最初被调用的对象。通常是 proxy 本身,但 handler 的 set 方法也有可能在原型链上,或以其他方式被间接地调用(因此不一定是
    proxy 本身)。

let validator = {
    set(target,prop,val){
        if(prop === 'age'){
            if(!Number.isInteger(val)){
                throw new TypeError('The age is not ange integer')
            }
            if(val>200){
                throw new RangeError('The age is invalid')
            }
        }
        target[prop] = val
    }
}

let person = new Proxy({},validator)

person.age = 100

console.log(person.age);

person.age = 2.2
person.age = 22222
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

在这里插入图片描述
注意,严格模式下,set代理如果没有返回true,就会报错。

在这里插入图片描述

用ES5的Object.defineProperty也可以实现拦截

用ES5的Object.defineProperty实现get和set的拦截也是可以的,但是由于此方法开始时是针对某个属性来设置的,所以需要一些操作,有点麻烦

// 用ES5的Object.defineProperty实现get的拦截  比较麻烦
const obj = {
    one: 1,
    two: 2,
    three: 3
}

for (var key in obj) {
    let val = obj[key]
    Object.defineProperty(obj, key, {
        get() {
            return val
        }
    })
}

console.log(obj.one); //1
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

get和set实现防止属性被读写

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


const handler = {
    get(target,prop){
        judgeMent(prop,'get')
        return target[prop]
    },
    set(target,prop){
        judgeMent(prop,'set')
        return true
    }
}

const proxyObj =new Proxy({_name:"Bob"},handler)

// proxyObj._name

proxyObj._age = 18
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

在这里插入图片描述

在这里插入图片描述

apply(target, object, args)

handler.apply() 方法用于拦截函数的调用,可以返回任何值

  • target 目标对象(函数)。
  • thisArg 被调用时的上下文对象。
  • argumentsList 被调用时的参数数组。
function sum(a, b) {
  return a + b;
}

const handler = {
  apply: function(target, thisArg, argumentsList) {
    console.log(`Calculate sum: ${argumentsList}`);
    // expected output: "Calculate sum: 1,2"

    return target(argumentsList[0], argumentsList[1]) * 10;
  }
};

const proxy1 = new Proxy(sum, handler);

console.log(sum(1, 2));
// expected output: 3
console.log(proxy1(1, 2));
// expected output: 30

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

has()

has方法用来拦截hasProperty操作,即判断对象是否具有某个属性时,这个方法会生效。典型的操作就是in运算符。( 但是对for in的操作不起作用 )

== handler.has() 方法是针对 in 操作符的代理方法。==


const handler = {
    has(target,prop){
        if(prop[0] === '_'){
            return false
        }
        return prop in target
    }
}

const target = {
    _secret:'easily scared',
    eyeCount:4
}

const proxyObj = new  Proxy(target,handler)

console.log('eyeCount' in proxyObj);
console.log('_secret' in proxyObj);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

在这里插入图片描述

construct方法

construct方法用于拦截new命令

  1. target 目标对象。
  2. argumentsList constructor的参数列表。
  3. newTarget
    最初被调用的构造函数,就上面的例子而言是p。

construct方法返回的必须是一个对象,否则会报错。

function monster1(disposition) {
  this.disposition = disposition;
}

const handler1 = {
  construct(target, args) {
    console.log('monster1 constructor called');
    // expected output: "monster1 constructor called"

    return new target(...args);
  }
};

const proxy1 = new Proxy(monster1, handler1);

console.log(new proxy1('fierce').disposition);
// expected output: "fierce"

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

还有一些不常用的方法请参照MDN

Proxy的this问题

在 Proxy 代理的情况下,目标对象内部的this关键字会指向 Proxy 代理。

在这里插入图片描述
上面代码中,一旦proxy代理target.m,后者内部的this就是指向proxy,而不是target。

在这里插入图片描述

上面代码中,目标对象jane的name属性,实际保存在外部WeakMap对象_name上面,通过this键区分。由于通过proxy.name访问时,this指向proxy,导致无法取到值,所以返回undefined。

用proxy对象实现数据的双向绑定

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>proxy实现双向绑定</title>
</head>
<body>
    <input type="text" id="input"/>
    <h1 id="h1"></h1>
    <script>
        let inp = document.querySelector('#input')
        let h1 = document.querySelector('#h1')


        let obj = {
            val:'1123'
        }

        let proxyObj = new Proxy(obj,{
            set(target,attr,value){

                target[attr] = value 
                inp.value = value
                h1.innerHTML = value
            }
        })

        proxyObj.val = obj.val //实现set,使输入框和p标签都显示obj.val值
        
        inp.addEventListener('input',function(){
            console.log(inp.value);
            proxyObj.val = inp.value  //数据同时变化
        })

        
    </script>
</body>
</html>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/从前慢现在也慢/article/detail/140209
推荐阅读
相关标签
  

闽ICP备14008679号