web前端—前端三剑客之JS-ES6(11):Proxy代理

  • Post author:
  • Post category:其他


菜鸟教程:

https://www.runoob.com/w3cnote/es6-reflect-proxy.html


目录


创建代理


Proxy的拦截操作方法


Proxy是在目标对象之前架设一层“拦截”,外界对该对象的访问,都必须先通过这层拦截,因此提供了一种机制,可以对外界的访问进行过滤和改写。

创建代理

es6中使用代理是通过new一个代理实例对象进行操作:new Proxy(target,handler)

参数说明:

  • target:表示所要拦截(代理)的目标对象
  • handler:是一个配置对象,对于每一个被代理的操作,需要提供一个对应的处理函数,该函数将拦截对应的操作。

Proxy的拦截操作方法

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>proxy</title>
</head>

<body>

    <button class="st">修正内容</button>
    <button class="gt">获得内容</button>
    <span
        style="color: rgb(72, 11, 184);"><strong>&emsp;&emsp;&emsp;obj的属性名:{name、nativeplace、password},password不允许修改</strong></span>
    <p></p>
    <script>
        // 被代理对象
        let obj = {
            name: '曹操',
            nativeplace: '沛国谯郡',
            password: '鸡肋'
        };

        // 代理方法
        let bt = document.querySelector('.st');
        let pd = document.querySelector('.gt');
        var setname = function () {
            let setkey = prompt('输入要修改的键');
            if (setkey == 'password') {
                proxy1.password = setkey;
            } else {
                let val = obj[setkey];
                if (val == undefined) {
                    alert`输入的键名不存在,请重新输入`;
                    setname();
                } else {
                    let newvalue = prompt('输入新的键值');
                    proxy1[setkey] = newvalue;
                    return;
                }
            };
        };
        var getpd = function () {
            let getkey = prompt('输入要获取的键');
            if (getkey == 'password') {
                let pd = prompt('输入我军口令');
                if (pd != '鸡肋') {
                    alert`口令错误,拉出去斩了!!!`;
                }
            } else {
                let val = obj[getkey];
                if (val == undefined) {
                    alert`输入的键名不存在,请重新获取`;
                    return;
                } else {
                    let hint = `${getkey}的值是:${obj[getkey]}`;
                    let p = document.querySelector('p');
                    p.innerHTML = `<span style="color:red;font-size:30px;">${hint}</span>`;
                    return;
                }
            }
        };

        let handler = {
            get: function (traget, key) {
                getpd();
            },
            set: function (traget, key, value) {
                if (key == 'password') {
                    alert`你无权修改口令`;
                } else {
                    if (value == traget[key]) {
                        alert`不能和之前相同,请重新输入`;
                        setname();
                    } else if (value == '') {
                        alert`修改内容不能为空`;
                        setname();
                    } else {
                        console.log(value);
                        alert`修改成功`;
                    }
                }
            }
        };

        // 创建代理
        let proxy1 = new Proxy(obj, handler);

        bt.onclick = function () {
            setname();
        };
        pd.onclick = function () {
            getpd();
        };
    </script>

</body>

</html>

get()



get(target, propKey, receiver)


:拦截对象属性的读取。

三个参数,依次为目标对象、属性名和 proxy 实例本身(严格地说,是操作行为所针对的对象,也就是所谓的接收器),其中最后一个参数可选。

set()



set(target, Key, value,receiver)


:用来拦截某个属性的赋值操作,对要赋值的数据进行过滤,加工或是权限设置

四个参数,依次为 目标对象、 属性名 、属性值 、Proxy 实例本身 其中最后一个参数可选。

注意,严格模式下(’use strict’;),set代理如果没有返回true,就会报错。

apply()

apply(target, object, args):拦截 Proxy 实例作为函数调用的操作

三个参数,分别是 目标对象(目标对象得是函数) 目标对象的上下文对象(this)(需要手动设置的) 目标对象的参数数组。

has()

has(target, propKey):拦截propKey in proxy的操作,返回一个布尔值。 has方法可以接受两个参数,分别是目标对象、需查询的属性名。

has方法用来拦截hasProperty操作,即判断对象是否具有某个属性时,这个方法会生效。典型操作是in运算符( 但对for… in的操作不起作用 )。has方法拦截的是HasProperty操作,而不是HasOwnProperty操作,即has方法不判断一个属性是对象自身的属性,还是继承的属性。

construct()

construct( target,args):用于拦截new命令。construct方法返回的必须是一个对象,否则会报错。两个参数:

target:目标对象

args:构造函数的参数对象

deleteProperty()

deleteProperty(target,key):拦截delete操作,如果这个方法抛出错误或者返回false,当前属性就无法被delete命令删除。

注意,目标对象自身的不可配置(configurable)的属性,不能被deleteProperty方法删除,否则报错。

defineProperty()

defineProperty(target,key,descriptor):拦截了Object.defineProperty操作。

如果目标对象不可扩展(non-extensible),则defineProperty不能增加目标对象上不存在的属性,否则会报错。另外,如果目标对象的某个属性不可写(writable)或不可配置(configurable),则defineProperty方法不得改变这两个设置。

getOwnPropertyDescriptor()

getOwnPropertyDescriptor(target,key):拦截Object.getOwnPropertyDescriptor(),返回一个属性描述对象或者undefined。

getPrototypeOf()

getPrototypeOf(target):用来拦截获取对象原型。包括:

  • Object.prototype.__proto__
  • Object.prototype.isPrototypeOf()
  • Object.getPrototypeOf()
  • Reflect.getPrototypeOf()
  • instanceof

getPrototypeOf方法的返回值必须是对象或者null,否则报错。另外,如果目标对象不可扩展(non-extensible), getPrototypeOf方法必须返回目标对象的原型对象。

isExtensible()

isExtensible(target):拦截Object.isExtensible操作

该方法只能返回布尔值,否则返回值会被自动转为布尔值。此方法有一个强限制,它的返回值必须与目标对象的isExtensible属性保持一致,否则就会抛出错误。

ownKeys()

ownKeys(target):用来拦截对象自身属性的读取操作。包括:

  • Object.getOwnPropertyNames()
  • Object.getOwnPropertySymbols()
  • Object.keys()
  • for…in循环

使用Object.keys方法时,有三类属性会被ownKeys方法自动过滤,不会返回。 目标对象上不存在的属性 属性名为 Symbol 值 不可遍历(enumerable)的属性:目标对象上不存在的属性、属性名为 Symbol 值、不可遍历(enumerable)的属性。

ownKeys方法返回的数组成员,只能是字符串或 Symbol 值(虽说Symbol会被忽略)。如果有其他类型的值,或者返回的根本不是数组,就会报错。

如果目标对象自身包含不可配置的属性,则该属性必须被ownKeys方法返回,否则报错。

如果目标对象是不可扩展的(non-extensible),这时ownKeys方法返回的数组之中,必须包含原对象的所有属性,且不能包含多余的属性,否则报错。

preventExtensions()

preventExtensions(target):拦截Object.preventExtensions()。该方法必须返回一个布尔值,否则会被自动转为布尔值。

这个方法有一个限制,只有目标对象不可扩展时(即Object.isExtensible(proxy)为false),proxy.preventExtensions才能返回true,否则会报错。

setPrototypeOf()

setPrototypeOf(target,proto):用来拦截Object.setPrototypeOf方法。该方法只能返回布尔值,否则会被自动转为布尔值

Proxy.revocable()

Proxy.revocable(traget,handler):返回一个可取消的 Proxy 实例。



版权声明:本文为JBY2020原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。