【ECMAScript】Proxy对象和Reflect对象的属性和方法梳理和总结(第七篇)

1. 前言

        ES6版本增加Proxy构造函数对象和Reflect对象,本文进行梳理和总结。

2.代理Proxy捕获器
代理捕获器 拦截操作 示例
defineProperty(target, property, descriptor)

Object.defineProperty(proxy, property, descriptor)

Reflect.defineProperty(proxy, property, descriptor)

const target = {};

const  proxy = new Proxy(

 target,

 defineProperty(target, property, descriptor) {

  return Reflect.defineProperty(...arguments)

 }

)

Object.defineProperty(proxy, 'foo', {

 value: 1,

})

// defineProperty()

deleteProperty(target, prproperty)

delete proxy.property

delete proxy[property]

Reflect.deleteProperty(proxy, property)

const target = {};

const  proxy = new Proxy(

 target,

 deleteProperty(target, property, descriptor) {

  return Reflect.deleteProperty(...arguments)

 }

)

delete proxy.foo

// deleteProperty(()

getOwnPropertyDescriptor(target, property)

Object.getOwnPropertyDescriptor(proxy, property)

Reflect.getOwnPropertyDescriptor(proxy, property)

onst target = {};

const  proxy = new Proxy(

 target,

 getOwnPropertyDescriptor(target, property) {

  return Reflect.getOwnPropertyDescriptor(...arguments)

 }

)

Object.getOwnPropertyDescriptor(proxy, 'foo')

// getOwnPropertyDescriptor()

get(target, propertyKey, receiver?)

proxy.property

proxy[property]

Object.create(proxy)[property]

Reflect.get(proxy, property, receiver)

const target = {};

const  proxy = new Proxy(

 target,

 get(target, property, receiver) {

  return Reflect.get(...arguments)

 }

)

proxy.foo

// get()

set(target, property, value, receiver?)

proxy.property = value

proxy[property] = value

Object.create(proxy)[property] = value

Reflect.set(proxy, proerpty, value, receiver)

const target = {};

const  proxy = new Proxy(

 target,

 set(target, property, receiver) {

  return Reflect.get(...arguments)

 }

)

proxy.foo = 1

// set()

has(target, property)

property in proxy

property in Object.create(proxy)

with(proxy) { (property); }

Reflect.has(proxy, property)

const target = {};

const  proxy = new Proxy(

 target,

 has(target, property) {

  return Reflect.has(...arguments)

 }

)

'foo' in proxy

// has()

getPrototypeOf(target)

Object.getPrototypeOf(proxy)

Reflect.getPrototypeOf(proxy)

proxy.__proto__

Object.prototype.isPrototypeOf(proxy)

proxy instanceof Object

const target = {};

const  proxy = new Proxy(

 target,

 getPrototypeOf(target) {

  return Reflect.getPrototypeOf(...arguments)

 }

)

Object.getPrototypeOf(proxy)

// gePrototypeOf()

setPrototypeOf(target, prototype)

Object.setPrototypeOf(proxy, ?)

Reflect.setPrototypeOf(proxy, ?)

const target = {};

const  proxy = new Proxy(

 target,

 setPrototypeOf(target, prototype) {

  return Reflect.setPrototypeOf(...arguments)

 }

)

Object.setPrototypeOf(proxy, Object)

// setPrototypeOf()

apply(target, thisArg, argsList)

proxy(...argsList)

Function.prototype.apply(thisArg, argsList)

Function.prototype.call(thisArg, ...argsList)

Reflect.apply(target, thisArg, argsList)

const target = () => {}; 

const  proxy = new Proxy(

 target,

 apply(target, thisArg, argsList) {

  return Reflect.apply(...arguments)

 }

)

proxy();

// apply()

construct(target, argsList, newTarget?)

new Proxy(...argsList)

Reflect.contruct(target, argsList, newTarget)

const target = function() {}; 

const  proxy = new Proxy(

 target,

 construct(target, argsList, newTarget) {

  return Reflect.construct(...arguments)

 }

)

new proxy();

// construct()

ownKeys(target)

Object.getOwnPropertyNames(proxy)

Object.getOwnPropertySymbols(proxy)

Object.keys(proxy)

Reflect.ownKeys(proxy)

const target = {};

const  proxy = new Proxy(

 target,

 ownKeys(target) {

  return Reflect.ownKeys(...arguments)

 }

)

Object.keys(proxy)

// ownKeys()

isExtensible(target)

Object.isExtensible(proxy)

Reflect.isExtensible(proxy)

const target = {};

const  proxy = new Proxy(

 target,

 isExtensible(target) {

  return Reflect.isExtensible(...arguments)

 }

)

Object.isExtensible(proxy)

// isExtensible()

preventExtensions(target)

Object.preventExtensions(proxy)

Reflect.preventExtensions(proxy)

const target = {};

const  proxy = new Proxy(

 target,

 preventExtensions(target) {

  return Reflect.preventExtensions(...arguments)

 }

)

Object.preventExtensions(proxy)

// preventExtensions()

3. Reflect静态方法

        Reflect静态方法比Object静态方法的优势是:方法执行出错时,不会抛出错误,而是返回false。

Reflect静态方法 说明 示例
Reflect.defineProperty(target, property, descriptor)

功能:基本等同于Object.defineProperty(),不同的Reflect是返回boolean值,Object是返回一个对象

输入:Object, any, Object

输出:boolean(即true } false)

let obj = {};

Reflect.defineProperty(obj, 'x', {

  value: 7

});

// 返回true

obj.x

得到7

Reflect.deleteProperty(target, prproperty)

功能:替代delete操作符,属性不存在会返回true,属性不可配置返回false

输入:Object | Array, any

输出:boolean(即true } false)

Reflect.deleteProperty({}, 'foo')

得到true

Reflect.deleteProperty(Object.freeze({

 foo: 1

}), 'foo')

得到false

Reflect.getOwnPropertyDescriptor(target, property)

功能: 返回目标对象指定property属性的描述符,Object.getOwnPropertyDescriptor相似,但target不是对象类型时,Object上的会强制类型转换,Reflect上的会抛出TypeError

输入:Object, any

输出:propertyDescriptor | undefined

Reflect.getOwnPropertyDescriptor({

 x: 'hello'

}, 'x')

得到

{value: 'hello', writable: true, enumerable: true, configurable: true}

Reflect.get(target, propertyKey, receiver?)

功能:获取target的property属性的值,与target[propertyKey]相似,替换对象属性访问操作符,如果target定义了getter,receiver是getter调用时的this值

输入:Object | Array, any, thisObject?

输出:any

obj = {a: 1, b: '123'};

Reflect.get(obj, a)

得到1

Reflect.set(target, property, value, receiver?)

功能:设置target的property属性值为value,替换=赋值操作符,如果target定义了setter,receiver是setter调用时的this值

输入:Object | Array, any, any, thisObject?

输出:boolean(即true } false)

obj = {a: 1, b: '123'};

Reflect.set(obj, c, true)

得到true

obj变成

{a: 1, b: '123', c: true};

Reflect.has(target, property)

功能:替代in操作时或with(),检查目标对象是否存在此属性

输入:Object, any

输出:输出:boolean(即true } false)

Reflect({ x: 0 }, 'x')

得到true

Reflect.getPrototypeOf(target)

功能:与Object.getPrototypeOf()相似,但target不是对象类型时,Object上的会强制类型转换,Reflect上的会抛出TypeError,返回指定对象的原型对象

输入:Object

输出:Object | null

Reflect.getPrototypeOf({})

得到Object.prototype

Reflect.setPrototypeOf(target, prototype)

功能:与Object.setPrototypeOf()相似,设置对象的原型,即修改对象__proto__指向

输入:

输出:输出:boolean(即true } false)

const obj1 = {};

Reflect.setPrototypeOf(obj1,

Object.prototype);

得到true

obj1.__proto__指向Object.prototype

Reflect.apply(target, thisArg, argsList)

功能:对一个函数对象进行调用操作,同时可传入数组作为调用参数,用于替换Function.prototype.apply.call(Math.floor, undefined, [1.75]);

输入:Function, thisObject, Array

输出:target执行结果

Reflect.apply(Math.floor, undefined, [1.75])

下取整得到1

Reflect.apply(String.fromCharCode, undefined, [104, 101, 108, 108, 111]),);

通过Unicode码得到字符串'hello'

Reflect.apply(RegExp.prototype.exec, /ab/, ['confabulation']).index;

相当于/ab/.exec('confabulation')

得到4

Reflect.construct(target, argsList, newTarget?)

功能:替代new操作符,如果newTarget存在,则相当于

obj=Object.create(newTarget.prototype)

target.apply(obj, argsList)

输入:Funtion, Array

输出:实例化对象

function Foo() { }

let obj = new Foo(...args)

obj = Reflect.contruct(Foo, args)

Reflect.ownKeys(target)

输入:类似于Object.keys(),但不受enumerable影响,等同于Object.getOwnPropertyNames(target)和Object.getOwnPropertySymbols(target)返回数组的concat结果,返回目标对象自身属性键组成的数组

输出:Array

sym = Symbol.for('comet');

obj = {

 a: 1,

 b: '123',

 [sym]: true

}

Reflect.ownKeys(obj);

得到['a', 'b', Symbol(comet)]

Reflect.isExtensible(target)

功能:判断一个对象是否可以扩展(即是否可以添加新属性),与Object.isExtensible()相似,但target不是对象类型时,Object上的会强制类型转换,Reflect上的会抛出TypeError

输入:Object

输出:boolean(即true } false)

Reflect.isExtensible(Object.seal({}))

得到false

Reflect.isExtensible(Object.freeze({}))

同样得到false
Reflect.preventExtensions(target)

功能:阻止目标对象扩展,与Object.preventExtensions()相似,但target不是对象类型时,Object上的会强制类型转换,Reflect上的会抛出TypeError

输入:Obejct

输出:boolean(即true } false)

empty = {}

Reflect.preventExtensions(empty)

返回true

4. 代理Proxy应用
  • 跟踪属性访问
const user = {
    name: 'Jake',
};

const proxy = new Proxy(
    user,
    {
        get(target, property, receive) {
            console.log(`Getting ${property}`);
            return Reflect.get(...arguments);
        },
        set(target, property, value, receive) {
            console.log(`Setting ${property}=${value}`);
            return Reflect.set(...arguments);
        }
    }
);

proxy.name; // Getting name
proxy.age = 27; // Setting age=27
  • 隐藏属性
const hiddenProperties = ['foo', 'bar'];
const targetObject = {
    foo: 1,
    bar: 2,
    baz: 3
};

const proxy = new Proxy(
    targetObject,
    {
        get(target, property, receive) {
            if(hiddenProperties.includes(property)) {
                return undefined
            } else {
                return Reflect.get(...arguments);
            }
        },
        has(target, property) {
            if(hiddenProperties.includes(property)) {
                return false;
            } else {
                return Reflect.set(...arguments);
            }
        }
    }
)

console.log(proxy.foo); // undefined
console.log(proxy.bar); // undefined
console.log(proxy.baz); // 3

console.log('foo' in proxy); // false;
console.log('bar' in proxy); // false
console.log('baz' in proxy) // true;
  • 属性验证
const target = {
    onlyNumberGoHere: 0
};

const proxy = new Proxy(
    target,
    {
        set(target, property, value) {
            if(typeof value !== 'number') {
                return false;
            } else {
                return Reflect.set(...arguments);
            }
        }
    }
);

proxy.onlyNumberGoHere = 1;
console.log(proxy.onlyNumberGoHere); // 1
proxy.onlyNumberGoHere = '2';
console.log(proxy.onlyNumberGoHere); // 1
  • 函数和构造函数参数验证
function median(...nums) {
    return nums.sort()[Math.floor(nums.length / 2)];
}

const proxy = new Proxy(
    median,
    {
        apply(target, thisArg, argsList) {
            for(const arg of argsList) {
                if(typeof arg !== 'number') {
                    throw 'Non-number argument provided';
                }
            }
            return Reflect.apply(...arguments);
        }
    }
)

console.log(proxy(4, 7, 1)); // 4
console.log(proxy(4, '7', 1)); // Error: Non-number argument provided

class User {
    constructor(id) {
        this.id_ = id;
    }
}

const proxy = new Proxy(
    User,
    {
        construct(target, argsList, newTarget) {
            if(argsList[0] === undefined) {
                throw 'User cannot be instantiated without id';
            } else {
                return Reflect.construct(...arguments);
            }
        }
    }
)

new proxy(1);

new proxy(); // Error: User cannot be instantiated without id
  • 数据绑定和可观察对象
const userList = [];

class User {
    constructor(name) {
        this.name_ = name;
    }
}

const proxy = new Proxy(
    User,
    {
        construct() {
            const newUser = Reflect.construct(...arguments);
            // 新实例化对象全部push到数组中
            userList.push(newUser);
            return newUser;
        }
    }
)

new proxy('John');
new proxy('Jacob');
new proxy('Jingleheimerschmidt');

onsole.log(userList); // [User {}, User {}, User{}]



function emit(newValue) {
    console.log(newValue);
}

const proxy = new Proxy(
    userList,
    {
        set(target, property, value, receiver) {
            const result = Reflect.set(...arguments);
            if(result) {
                // 每次更新target的property属性的值,成功后,则emit掉
                emit(Reflect.get(target, property, receiver));
            }
            return result;
        }
    }
)

proxy.push('John');
// John
proxy.push('Jacob');
// Jacob

下一篇:【ECMAScript】Object对象的属性和方法梳理和总结(第八篇)-CSDN博客 

注:以上,如有不合理之处,还请帮忙指出,大家一起交流学习~

你可能感兴趣的:(ecmascript,前端,开发语言)