Object.defineProperty()
const obj = {
name: '小黑',
age: 18
}
Object.keys(obj).forEach(key => {
let value = obj[key]
Object.defineProperty(obj, key, {
get() {
console.log(`obj.${key}被访问`);
return value
},
set(newValue) {
console.log(`obj.${key}被修改`);
value = newValue
},
})
})
obj.name = "小白"
console.log(obj.name);
obj.age = 12
console.log(obj.age);
注意:它没有办法监听更加丰富的操作,只能监听获取和修改
Proxy的基本使用
const obj = {
name: '小黑',
age: 18
}
// Proxy 参数一:需要代理的对象 参数二:捕获器 例如捕获增加,删除等
// 可以修改原对象
const objProxy = new Proxy(obj, {
// target 原对象 key对象的key
get(target, key) {
console.log("属性被访问");
return target[key]
},
// newValue 新值
set(target, key, newValue) {
console.log("属性被修改");
target[key] = newValue
}
})
objProxy.name = '小白'
objProxy.age = 12
console.log(objProxy.name);
console.log(objProxy.age);
// console.log(obj.name);
// console.log(obj.age);
proxy的所有捕获器
-
get(target, propKey, receiver):拦截对象属性的读取,比如proxy.foo
和proxy['foo']
。
-
set(target, propKey, value, receiver):拦截对象属性的设置,比如proxy.foo = v
或proxy['foo'] = v
,返回一个布尔值。
-
has(target, propKey):拦截propKey in proxy
的操作,返回一个布尔值。
-
deleteProperty(target, propKey):拦截delete proxy[propKey]
的操作,返回一个布尔值。
-
ownKeys(target):拦截Object.getOwnPropertyNames(proxy)
、Object.getOwnPropertySymbols(proxy)
、Object.keys(proxy)
、for...in
循环,返回一个数组。该方法返回目标对象所有自身的属性的属性名,而Object.keys()
的返回结果仅包括目标对象自身的可遍历属性。
-
getOwnPropertyDescriptor(target, propKey):拦截Object.getOwnPropertyDescriptor(proxy, propKey)
,返回属性的描述对象。
-
defineProperty(target, propKey, propDesc):拦截Object.defineProperty(proxy, propKey, propDesc)
、Object.defineProperties(proxy, propDescs)
,返回一个布尔值。
-
preventExtensions(target):拦截Object.preventExtensions(proxy)
,返回一个布尔值。
-
getPrototypeOf(target):拦截Object.getPrototypeOf(proxy)
,返回一个对象。
-
isExtensible(target):拦截Object.isExtensible(proxy)
,返回一个布尔值。
-
setPrototypeOf(target, proto):拦截Object.setPrototypeOf(proxy, proto)
,返回一个布尔值。如果目标对象是函数,那么还有两种额外操作可以拦截。
-
apply(target, object, args):拦截 Proxy 实例作为函数调用的操作,比如proxy(...args)
、proxy.call(object, ...args)
、proxy.apply(...)
。
-
construct(target, args):拦截 Proxy 实例作为构造函数调用的操作,比如new proxy(...args)
。
Reflect
Reflect
对象与Proxy
对象一样,也是 ES6 为了操作对象而提供的新 API。
Reflect和Proxy结合使用
const obj = {
name: '小黑',
age: 18
}
const objProxy = new Proxy(obj, {
get(target, key, receiver) {
console.log("属性被访问");
// return target[key]
return Reflect.get(target, key)
},
set(target, key, newValue, receiver) {
console.log("属性被修改");
Reflect.set(target, key, newValue)
}
})
objProxy.name = '小白'
objProxy.age = 12
console.log(objProxy.name);
console.log(objProxy.age);
Proxy主要就是不希望修改原本的对象,Reflect刚好解决这个问题
Reflect的方法有返回值,可以返回是否设置成功的布尔值
Receiver的作用
const obj = {
_name: "小黑", // 下划线是常用标记,表示是内部属性,只能通过对象的方法进行读写
get name() {
return this._name
},
set name(newValue) {
this._name = newValue
}
}
const objProxy = new Proxy(obj, {
get(target, key, receiver) {
// receiver 是代理对象
console.log(key);
return Reflect.get(target, key, receiver) // receiver改变target对象get方法的this
},
set(target, key, newValue, receiver) {
console.log(key);
Reflect.set(target, key, newValue, receiver)
}
})
objProxy.name = "小白"
console.log(objProxy.name);
Reflect.construct(target,argumentsList,newTarget)
function Student(name, age) {
this.name = name
this.age = age
}
function Teacher() { }
// 执行Student的内容,创建Teacher对象
const teacher = Reflect.construct(Student, ['小黑', 18], Teacher)
console.log(teacher);
console.log(teacher.__proto__ === Teacher.prototype);
Proxy响应式
// 收集依赖的响应式函数
let activeReactiveFn = null
class Depend {
constructor() {
// 依赖收集
this.reactiveFns = new Set()
}
// addDepend(reactiveFns) {
// this.reactiveFns.add(reactiveFns)
// }
depend() {
if (activeReactiveFn) {
this.reactiveFns.add(activeReactiveFn)
}
}
notify() {
this.reactiveFns.forEach(fn => {
fn()
})
}
}
// 响应式函数
const depend = new Depend()
function watchFn(fn) {
activeReactiveFn = fn
fn()
activeReactiveFn = null
}
// 封装获取depend的函数
const targetMap = new WeakMap()
function getDepend(target, key) {
// 根据target对象获取map的过程
let map = targetMap.get(target)
if (!map) {
map = new Map()
targetMap.set(target, map)
}
// 根据key获取depend对象
let depend = map.get(key)
if (!depend) {
depend = new Depend()
map.set(key, depend)
}
return depend
}
// 响应式对象的封装
function reactive(obj) {
return new Proxy(obj, {
get(target, key, receiver) {
// 根据target, key获取对应的depend
const depend = getDepend(target, key)
// 添加函数
depend.depend()
return Reflect.get(target, key, receiver) // receiver改变target对象get方法的this
},
set(target, key, newValue, receiver) {
Reflect.set(target, key, newValue, receiver)
// 根据target, key获取对应的depend
const depend = getDepend(target, key)
depend.notify()
}
})
}
// 对象的响应式
const objProxy = reactive({
name: '小黑',
age: 18
})
const infoProxy = reactive({
address: '武汉',
})
watchFn(function () {
console.log(objProxy.name, '---------------');
console.log(objProxy.name, '+++++++++++++++');
})
watchFn(function () {
console.log(infoProxy.address, '---------------');
console.log(infoProxy.address, '+++++++++++++++');
})
objProxy.name = '小白'
infoProxy.address = '深圳'
Object.defineProperty响应式
// 收集依赖的响应式函数
let activeReactiveFn = null
class Depend {
constructor() {
// 依赖收集
this.reactiveFns = new Set()
}
depend() {
if (activeReactiveFn) {
this.reactiveFns.add(activeReactiveFn)
}
}
notify() {
this.reactiveFns.forEach(fn => {
fn()
})
}
}
// 响应式函数
const depend = new Depend()
function watchFn(fn) {
activeReactiveFn = fn
fn()
activeReactiveFn = null
}
// 封装获取depend的函数
const targetMap = new WeakMap()
function getDepend(target, key) {
// 根据target对象获取map的过程
let map = targetMap.get(target)
if (!map) {
map = new Map()
targetMap.set(target, map)
}
// 根据key获取depend对象
let depend = map.get(key)
if (!depend) {
depend = new Depend()
map.set(key, depend)
}
return depend
}
// 响应式对象的封装
function reactive(obj) {
Object.keys(obj).forEach(key => {
let value = obj[key]
Object.defineProperty(obj,key, {
get() {
const depend = getDepend(obj, key)
depend.depend()
return value
},
set(newvalue) {
value = newvalue
const depend = getDepend(obj, key)
depend.notify()
}
})
})
return obj
}
// 对象的响应式
const objProxy = reactive({
name: '小黑',
age: 18
})
const infoProxy = reactive({
address: '武汉',
})
watchFn(function () {
console.log(objProxy.name, '---------------');
console.log(objProxy.name, '+++++++++++++++');
})
watchFn(function () {
console.log(infoProxy.address, '---------------');
console.log(infoProxy.address, '+++++++++++++++');
})
objProxy.name = '小白'
infoProxy.address = '深圳'