携手创作,共同成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第2天,点击查看活动详情
Reflect
Reflect 是一个内置的对象,它提供拦截 JavaScript 操作的方法。这些方法与Proxy() 的方法相同。Reflect不是一个函数对象,因此它是不可构造的。
简单使用
const target = {};
// 添加属性
Reflect.set(target, "abc","123");
// 获取值
console.log(Reflect.get(target,"abc"));
Reflect.get(target, propertyKey[, receiver]);
Reflect.set(target, propertyKey, value[, receiver]);
而set和get都有设置this指向的值
receiver则为调用时的this值
const obj = {
a: 2,
get b() {
return this.a;
},
};
const obj2 = {
a: 10,
};
console.log(Reflect.get(obj, "b", obj2)); // 10
对象的操作方式,都有对应的api,reflect使用请参考Reflect - JavaScript | MDN
// 普通写法
'assign' in Object // true
// Reflect写法
Reflect.has(Object, 'assign') // true
// 普通写法
Function.prototype.apply.call(Math.floor, undefined, [1.88]) // 1
// Reflect写法
Reflect.apply(Math.floor, undefined, [1.88]) // 1
// 普通写法
delete myObj.foo;
// Reflect写法
Reflect.deleteProperty(myObj, 'foo');
// new 的写法
const instance = new Greeting('张四');
// Reflect.construct 的写法
const instance = Reflect.construct(Greeting, ['礼物']);
// 普通写法
Object.defineProperty(obj, 'now', {
value: () => Date.now()
});
// Reflect写法
Reflect.defineProperty(obj, 'now', {
value: () => Date.now()
});
Proxy实现响应式
// 原对象:代理过的对象
const proxyMap = new WeakMap();
// 代理过的对象:原对象
const rawMap = new WeakMap();
function observer(obj, cb) {
const existingProxy = proxyMap.get(obj);
// 添加缓存 防止重新构建proxy
if (existingProxy) {
return existingProxy;
}
// 已经代理过
if (rawMap.has(obj)) {
return obj;
}
const proxy = new Proxy(obj, {
set(target, p, value, receiver) {
const ret = Reflect.set(target, p, value, receiver);
cb();
return ret;
},
get(target, p, receiver) {
const res = Reflect.get(target, p, receiver);
// res当为对象时代理它
return res && typeof res === "object" ? observer(res, cb) : res;
},
deleteProperty(target, p) {
const ret = Reflect.deleteProperty(target, p);
cb();
return ret;
},
});
proxyMap.set(obj, proxy);
rawMap.set(proxy, obj);
return proxy;
}
例子
const init = {
_name: "abc",
get name() {
return this._name;
},
a: {
c: [1, 2, 35, 6],
},
};
const ret = observer(init, () => {
// 当值改变时触发
console.log(ret);
console.log(init);
document.body.innerHTML = ret.name;
});
以上是数据响应式的实现,当对对象深层赋值时在get判断获取到的值是否为对象,若是设置为代理,若否着直接返回值,而数据的变化一般都是赋值、获取值、删除值。
使用WeakMap是避免内存泄露,它的key必须是对象,并且是弱引用,当key给设置为null,给垃圾回收时,当前的在WeakMap设置也会跟着给回收
封装为react的响应式数据hook
const useReactive = (initState) => {
const [, update] = useState({});
const stateRef = useRef(initState);
const isInit = useRef(true);
if (isInit.current) {
isInit.current = false;
stateRef.current = observer(initState, () => update({}));
}
return stateRef.current;
};
这里使用ref进行数据的储存,当数据改变的强制渲染组件以达到数据的更新
而一般需要这种场景的是既要数据实时,又要数据改变触发渲染,以此界面展示达到预期