ES6 Proxy实例方法总结

我心飞翔 分类:javascript

Proxy中方法枚举

handler方法 触发方式
get 读取某个属性
set 写入某个属性
has in操作符
deleteProperty delete操作符
getPrototypeOf Object.getPrototypeOf()
setPrototypeOf Object.setPrototypeOf()
isExtensible Object.isExtensible()
preventExtensions Object.preventExtensions()
getOwnPropertyDescriptor Object.getOwnPropertyDescriptor()
defineProperty Object.defineProperty()
ownKeys Object.getOwnPropertyNames()、Object.getOwnPropertySymbols()
apply 调用一个函数
construct 用new调用一个函数

Proxy方法实际应用

get()

get方法用于监听某个属性的读取操作,可以接受三个参数,依次为代理目标对象、读取的属性名称和 Proxy 实例本身(严格地说,是操作行为针对的对象),其中最后一个参数可选。

const person = {
    name: 'Lucky',
    age: 20,
}

const personProxy = new Proxy(person, {
    // 设置接收两个参数:代理目标对象,读取的属性名称
    get(target, property) {
        if (property in target) {
           return target[property]
        }
        throw new ReferenceError(`Property '${property}' does not exist.`);
    },
})

console.log(personProxy.name); // Lucky
console.log(personProxy.add); // 报错 Property 'add' does not exist.
 

上面代码在get中设置了如果读取目标对象不存在的属性,会抛出一个错误。正常情况下读取对象不存在的属性,只会返回undefined。

set()

set方法用来监听某个属性的赋值操作,可以接受四个参数,依次为代理目标对象、设置的属性名称、设置的属性值和 Proxy 实例本身,其中最后一个参数可选。

const person = {
    name: 'Lucky',
    age: 20,
}

const personProxy = new Proxy(person, {
    // 三个参数:代理目标对象,写入的属性名称, 属性值
    set(target, property, value) {
        if (property === 'age') {
            if (!Number.isInteger(value)) {
                throw new TypeError(`'${value}' is not a int`)
            }
        }
        target[property] = value
    },
})

personProxy.age = 123
personProxy.age = 'woshiLucky' // 报错  'woshiLucky' is not a int
 

上面的代码中监听到改变对象属性值的时候对age字段进行了必须是数字的处理,如果更改的值不是数字类型则抛出错误。

has()

has方法用来监听 HasProperty 操作,即判断对象是否具有某个属性时,这个方法会生效。典型的操作就是 in 运算符。
has 方法可以接受两个参数,分别是代理目标对象、需查询的属性名。

const person = {
    name: 'Lucky',
    age: 20,
}

const personProxy = new Proxy(person, {
    // 两个参数:代理目标对象,需要判断是否存在的属性名称
    has(target, property) {
        // 将返回结果取反
        return !(property in target)
    },
})

console.log('age' in personProxy); // false
console.log('add' in personProxy); // true
 

上面的代码中监听到in运算符使用的时候对结果进行了取反的处理,使对象中包含的属性返回false。

deleteProperty()

deleteProperty方法用于监听 delete 操作符,如果这个方法抛出错误或者返回 false,当前属性就无法被 delete 命令删除。

const person = {
    name: 'Lucky',
    age: 20,
}

const personProxy = new Proxy(person, {
    // 两个参数:代理目标对象,属性名称
    deleteProperty (target, property) {
        // 当属性为age时不做处理
        property !== 'age' && delete target[property];
    }
})

delete personProxy.age
delete personProxy.name
console.log(person);
 

上面的代码中监听到 delete 运算符,对age字段不做删除处理。

getPropertyOf()

getPropertyOf方法主要用来监听获取对象原型。主要是监听Object.getPrototypeOf()方法。接收一个参数,代理目标对象。

const person = {
    name: 'Lucky',
    age: 20,
}
const person1 = {}

const personProxy = new Proxy(person, {
    // 参数:当前目标对象
    getPrototypeOf(target) {
        return person1;
    },
})

console.log(Object.getPrototypeOf(personProxy) === person); // false
 

上面代码中代理的对象是person,在监听到getPrototypeOf方法时返回了person1的对象,所以personProxy不等于person

setPrototypeOf()

setPrototypeOf方法主要用来监听设置对象原型Object.setPrototypeOf()方法。接收两个参数,分别是:需要改变原型的对象、提供原型的对象。

const person = {
    name: 'Lucky',
    age: 20,
}
const person1 = {}

const personProxy = new Proxy(person, {
    // 两个参数:代理目标对象,属性名称
    setPrototypeOf(target, proto) {
        console.log(target, proto, target === proto);
        if (target !== proto) {
            return true
        }
        throw Error('The target object is the same as the current object.')
    },
})
Object.setPrototypeOf(personProxy, person1)
Object.setPrototypeOf(personProxy, person) // 报错  The target object is the same..
 

上面代码重新定义了原型链循环时的报错信息。

isExtensible()

isExtensible方法主要用来监听判断一个对象是否是可扩展的(是否可以在它上面添加新的属性) Object.isExtensible()方法,返回一个布尔值。

const person = {
    name: 'Lucky',
    age: 20,
}
const personProxy = new Proxy(person, {
    // 参数:当前目标对象
    isExtensible(target) {
        console.log('isIn');
        return true;
    },
})
Object.isExtensible(personProxy)
// isIn
// true
 

上面代码中监听到isExtensible的执行打印‘isIn

preventExtensions()

preventExtensions方法主要用来监听让一个对象变的不可扩展,也就是永远不能再添加新的属性的Object.preventExtensions()方法,该方法必须返回一个布尔值,否则会被自动转为布尔值。
这个方法有一个限制,只有目标对象不可扩展时(即Object.isExtensible(proxy)为false),proxy.preventExtensions 才能返回 true,否则会报错

const person = {
    name: 'Lucky',
    age: 20,
}
const personProxy = new Proxy(person, {
    // 参数:当前目标对象
    preventExtensions(target) {
        console.log('isIn');
        Object.preventExtensions(target);
        return true;
    },
})
Object.preventExtensions(personProxy)
 

getOwnPropertyDescriptor()

getOwnPropertyDescriptor方法主要用来监听Object.getOwnPropertyDescriptor()
Object.getOwnPropertyDescriptor()方法返回指定对象上一个自有属性对应的属性描述符。(自有属性指的是直接赋予该对象的属性,不需要从原型链上进行查找的属性)

const person = {
    name: 'Lucky',
    age: 20,
}
const personProxy = new Proxy(person, {
    // 两个参数:代理目标对象,属性名称
    getOwnPropertyDescriptor(target, property) {
        if (property === 'name') return
        return Object.getOwnPropertyDescriptor(target, property);
    },
})
console.log(Object.getOwnPropertyDescriptor(personProxy, 'age')); 
// { value: 20, writable: true, enumerable: true, configurable: true }
console.log(Object.getOwnPropertyDescriptor(personProxy, 'name'));
//undefined
 

上面代码中在获取name时处理,返回undefined

defineProperty()

defineProperty方法主要用来监听Object.defineProperty() 方法。
Object.defineProperty() 方法会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性,并返回此对象

const person = {
    name: 'Lucky',
    age: 20,
}
const personProxy = new Proxy(person, {
    // 两个参数:代理目标对象,属性名称,要定义或修改的属性描述符(Object)
    defineProperty(target, property, valueObj) {
        target[property] = valueObj.value;
        return true
    },
})
personProxy.gender = 'female';
console.log(personProxy); // { name: 'Lucky', age: 20, gender: 'female' }
 

ownKeys()

ownKeys方法主要用来监听对象自身属性的读取操作

  • Object.getOwnPropertyNames()
  • Object.getOwnPropertySymbols()
  • Object.keys()
  • for...in 循环
const person = {
    name: 'Lucky',
    age: 20,
}
const personProxy = new Proxy(person, {
    // 参数:代理目标对象
    ownKeys(target) {
        return Object.keys(target)
    },
})

console.log(Object.keys(personProxy));
 

apply()

apply方法主要用来监听函数调用call 和 apply 操作。
apply 方法可以接受三个参数,分别是目标对象、目标对象的上下文对象(this)和目标对象的参数数组。

const target = () => 'Target';
const targetProxy = new Proxy(target, {
    // 三个参数:目标对象、目标对象的上下文对象(this)和目标对象的参数数组
    apply (target, ctx, args) {
        return 'apply'
    }
})

console.log(targetProxy()); // apply
 

construct()

construct方法主要用来监听new 命令。
construct 方法可以接受三个参数。分别是目标对象、构造函数的参数对象和创造实例对象时,new 命令作用的构造函数。

class TargetObj {
    construct() {
        this.a = 'new'
    }
}
const targetProxy = new Proxy(TargetObj, {
    // 三个参数:目标对象、目标对象的上下文对象(this)和目标对象的参数数组
    construct (targets, args) {
        console.log(targets, args);
        return args
    }
})

console.log(new targetProxy(1, 2, 3)); // [1, 2, 3]
 

回复

我来回复
  • 暂无回复内容