Proxy学习

Proxy使用

Proxy是一个类,要new来实例化

let o = new Proxy(target,handler)
  • target指要代理的对象
  • handler一个对象,对target操作进行拦截的对象
    举例:
let obj = {name: 'brook'};
let p = new Proxy(obj, {
    get(target, property) {
        console.log(target, property);//{ name: 'brook' } 'name'
        return target[property];
    }
});

console.log(p.name); // 'brook

pobj的代理,里面写了get函数进行拦截,访问属性时的操作

  • get(target,property)
    • targetobj对象
    • property是访问的属性名这里是name

Proxy可拦截的操作

get

get(target, propKey, receiver)

  • taget是目标对象
  • propKey被拦截到的属性名
  • receivernew出的Proxy对象

拦截 以下操作

  • 访问属性: proxy[key]proxy.key
  • 访问原型链上的属性: Object.create(proxy)[key]
  • Reflect.get()

通过Proxy来让数组支持索引位负的情况


let arr = ["b", "r", "o", "o", "k"]
let p = new Proxy(arr, {
    get(target, property) {
        console.log(property)
        let index = Math.abs(Number(property))  // 取负数的绝对值
        return arr[index]
    }
})
console.log(p[-2])  //输出o

set

set(target, propKey, value, receiver)

  • value拦截到的赋值
  • receiver一般为proxy对象, 若proxy对象在原型链上(此时就不是proxy对象)
  • 必须返回布尔值,true表示成功,false失败

拦截 以下操作

  • 赋值属性: proxy[key]=valproxy.key=val
  • 访问原型链上的属性: Object.create(proxy)[key] = val
  • Reflect.set()

数组赋值时不是number类型就赋值0

let arr: any[] = [];
let p = new Proxy(arr, {
    set(target, property, value, receiver) {
        if (typeof value != 'number') {  // 不是number就设为0
            value = 0;
        }
        target[property] = value
        return false;
    }
});

p[0] = 11;
p[1] = 'brook';

console.log(p[0]); // 11
console.log(p[1]); // 

receiver对象不是proxy时

let o: { name: any } = {name: ""}
let p = new Proxy(o, {
    set: function (target, property, value, receiver) {
        console.log(receiver)
        target[property] = value
        return true
    }
});
p.name = 1 
let o2 = Object.create(p)
o2.name = 2
//第一次log { name: '' } p对象 
//第二次log {} o2对象

apply

apply(target, thisArg, arguments)

  • target目标对象(函数)
  • thisArg被调用时的上下文对象
  • arguments被调用时的参数列表
  • 可以返回任意值

拦截 以下操作

  • proxy(...args)
  • Function.prototype.apply()Function.prototype.call()
  • Reflect.apply()
let o = {
    sum: function (a, b) {
        return a + b;
    }
}
const handler = {
    apply: function (target, thisArg, argumentsList) {
        console.log(thisArg === newO) // true
        return target(argumentsList[0], argumentsList[1]) * 10;
    }
};

let newO = {sum: new Proxy(o.sum, handler)}
console.log(newO.sum(1, 2));

construct

construct(target, argumentsList, proxy)

  • target 目标对象
  • argumentsList constructor参数列表
  • proxy proxy对象

拦截 以下操作

  • 拦截new操作符new proxy(...args)
  • Reflect.construct()
function monster1(disposition) {
    this.disposition = disposition
}

const handler1 = {
    construct(target, args, proxy) {
        return new target(...args)
    }
}

const proxy1 = new Proxy(monster1, handler1)
new proxy1('fierce')

has

has(target, prop)

  • target 目标对象
  • prop 进行检查是否纯在的属性
  • return需要返回一个boolean属性值

拦截 以下操作

  • 主要针对in操作的钩子
  • 属性查询:key in proxy
  • 继承属性查询: key in Object.create(proxy)
  • with检查:with(proxy){(key)}
  • Reflect.has()
let p = new Proxy({}, {
    has: function (target, prop) {
        return true
    }
});
console.log(p) // {}
console.log('a' in p) // true
console.log('a' in Object.create(p)) //true

getPrototypeOf

getPrototypeOf(target)

  • target 目标对象
  • return需要返回一个object或null

拦截 以下操作

  • instanceof
  • __proto__
  • Object.getPrototypeOf()
  • Object.prototype.isPrototypeOf()
  • Reflect.getPrototypeOf()
let obj = {}
let p = new Proxy(obj, {
    getPrototypeOf(target) {
        return Array.prototype
    }
})
console.log(
    Object.getPrototypeOf(p) === Array.prototype,  // true
    Reflect.getPrototypeOf(p) === Array.prototype, // true
    p.__proto__ === Array.prototype,               // true
    Array.prototype.isPrototypeOf(p),              // true
    p instanceof Array                             // true
)

setPrototypeOf

getPrototypeOf(target,prototype)

  • target 目标对象
  • prototype 对象新原型或为null
  • return若成功修改你要返回true,否则返回false

拦截 以下操作

  • Object.setPrototypeOf()
  • Reflect.setPrototypeOf()
let handlerReturnsFalse = {
    setPrototypeOf(target, newProto) {
        Object.setPrototypeOf(target, newProto)
        return true
    }
}
let o = {a: 1}
let p1 = new Proxy({}, handlerReturnsFalse)
console.log(Object.getPrototypeOf(p1)) //{}
Object.setPrototypeOf(p1, o)
console.log(Object.getPrototypeOf(p1)) //{a:1}

deleteProperty

deleteProperty(target,property)

  • target 目标对象
  • property 待删除的属性名
  • return若删除成功,你要返回true,否则返回false

拦截 以下操作

  • 删除属性: delete proxy[foo]delete proxy.foo
  • Reflect.deleteProperty()
let p = new Proxy({a: 1}, {
    deleteProperty: function (target, prop) {
        delete target[prop]
        return true
    }
})
console.log(p) // { a: 1 }
delete p.a 
console.log(p) // {}

ownKeys

ownKeys(target)

  • target 目标对象
  • return 必须返回一个可枚举对象,且元素类型必须是StringSymbol

拦截

  • Object.keys()
  • Object.getOwnPropertyNames()
  • Object.getOwnPropertySymbols()
  • Reflect.ownKeys()
  • 具体效果看代码
let p = new Proxy({z: 1, x: 1}, {
    ownKeys: function (...arg) {
        return [Symbol(), 'k', 'z']
    }
})

console.log(Object.keys(p)) //[ 'z' ]
console.log(Object.getOwnPropertyNames(p))//[ 'k', 'z' ]
console.log(Object.getOwnPropertySymbols(p))//[ Symbol() ]

还有一些不常用的方法

  • defineProperty()
    • 用于拦截对对象的Object.defineProperty() 操作。
  • getOwnPropertyDescriptor()
    • 用于拦截对对象的Object.getOwnPropertyDescriptor() 操作。
  • isExtensible
    • 用于拦截对对象的Object.isExtensible() 操作。
  • preventExtensions()
    • 用于拦截对对象的Object.preventExtensions() 操作。

你可能感兴趣的:(Proxy学习)