Vue3.x中使用的 JS Proxy 代理

365 阅读3分钟

Proxy

Proxy 对象用于定义基本操作的自定义行为

语法

const p = new Proxy(target, handler)

参数

target

要使用 Proxy 包装的目标对象(可以是任何类型的对象,包括原生数组,函数,甚至另一个代理)。

handler

一个通常以函数作为属性的对象,各属性中的函数分别定义了在执行各种操作时代理 p 的行为。

handler 对象的方法

handler 对象是一个容纳一批特定属性的占位符对象。它包含有 Proxy 的各个捕获器(trap)。

所有的捕捉器是可选的。如果没有定义某个捕捉器,那么就会保留源对象的默认行为。

1、handler.get() 属性读取操作的捕捉器。

语法
let p = new Proxy(target, {
  get (target, property, receiver) {
    console.log(target, property, receiver)
  }
});
参数
target

目标对象。

property

被获取的属性名。

receiver

Proxy或者继承Proxy的对象

示例
let person = {
	name: 'Bob',
	age: 18
}
person = new Proxy(person, {
	get (target, key, r) {
		console.log(target, key, r)
		return target[key]
	}
})
console.log(person.name)
// target {name: "Bob", age: 18}
// key "name" 
// r Proxy {name: "Bob", age: 18}

2、handler.set() 属性设置操作的捕捉器。

语法
const p = new Proxy(target, {
  set (target, property, value, receiver) {
    console.log(target, property, value, receiver)
  }
});
参数
target

目标对象。

property

将被设置的属性名或 Symbol。

value

新属性值。

receiver

最初被调用的对象。

示例
let person = {
	name: 'Bob',
	age: 18
}
person = new Proxy(person, {
	get (target, key, r) {
		return target[key]
	},
	set (target, property, value, receiver) {
		console.log(target, property, value, receiver)
		target[property] = value
	}
})
person.name = 'Alice'
console.log(person.name)

// target {name: "Bob", age: 18} 
// property "name" 
// value "Alice" 
// receiver Proxy {name: "Bob", age: 18}

// person.name Alice
返回值

set() 方法应当返回一个布尔值。

  • 返回 true 代表属性设置成功。
  • 在严格模式下,如果 set() 方法返回 false,那么会抛出一个 TypeError 异常。

3、handler.defineProperty() Object.defineProperty 方法的捕捉器。

语法
const p = new Proxy(target, {
    defineProperty (target, property, descriptor) {
		console.log(target, property, descriptor)
	}
})
参数
target

目标对象。

property

待检索其描述的属性名。

descriptor

待定义或修改的属性的描述符。

返回值

defineProperty 方法必须以一个 Boolean 返回,表示定义该属性的操作成功与否。

示例
let person = {
	name: 'Bob',
	age: 18
}
person = new Proxy(person, {
	defineProperty (target, property, descriptor) {
		console.log(target, property, descriptor)
		target[property] = descriptor
		return true
	}
})
let desc = { configurable: true, enumerable: true, value: 10 };
Object.defineProperty(person, 'a', desc)
console.log(person)

// target {name: "Bob", age: 18} 
// property "a" 
// descriptor {value: 10, enumerable: true, configurable: true}

// person Proxy {name: "Bob", age: 18, a: {…}}
proxy 数组方法
let arr = [{a: 1, b: 2}, {a: 2, b: 2}, {a: 3, b: 2}, {a: 4, b: 2}]

arr = new Proxy(arr, {
	defineProperty(t, p, desc) {
		console.log(t, p, desc)
		Reflect.set(t, p, desc.value)
		return true
	}
})

// 能触发 handler defineProperty 方法
arr.push()
arr.pop()
arr.reverse()
...

4、handler.deleteProperty() delete 操作符的捕捉器。

语法
var p = new Proxy(target, {
  deleteProperty (target, property) {
  }
});
参数
target

目标对象。

property

待删除的属性名。

示例
let cat = {pz: 'bos', age: 2, animal: 'Cat'}
cat = new Proxy(cat, {
	deleteProperty (target, property) {
		console.log(target, property)
		Reflect.deleteProperty(target, property)
	}
})
delete cat.pz
console.log(cat)

// target {pz: "bos", age: 2, animal: "Cat"}
// property "pz"
// cat Proxy {age: 2, animal: "Cat"}

5、handler.has() in 操作符的捕捉器。

语法
var p = new Proxy(target, {
  has (target, prop) {
  }
});
参数
target

目标对象.

prop

需要检查是否存在的属性.

示例
let cat = {pz: 'bos', age: 2, animal: 'Cat'}
cat = new Proxy(cat, {
	has (target, property) {
		console.log(target, property)
		return Reflect.has(target, property)
	}
})
console.log('pz' in cat)
// target {pz: "bos", age: 2, animal: "Cat"} 
// property "pz"

// true

6、handler.ownKeys() Object.getOwnPropertyNames 方法和 Object.getOwnPropertySymbols 方法的捕捉器。

语法
let p = new Proxy(target, {
    ownKeys (target) {
    }
})
参数
target

目标对象.

示例
let a = Symbol()
let cat = {pz: 'bos', age: 2, animal: 'Cat'}
cat[a] = 'this is symbol value'
cat = new Proxy(cat, {
	ownKeys (target) {
		console.log(target)
		return Reflect.ownKeys(target)
	}
})
console.log(Object.getOwnPropertyNames(cat))
console.log(Object.getOwnPropertySymbols(cat))

// target {pz: "bos", age: 2, animal: "Cat", Symbol(): "this is symbol value"}

// ["pz", "age", "animal"]
// [Symbol()]