扇贝听力
126.68M · 2026-02-26
在实际开发中,我们常常会面临各种需求:
const config = readonly({ api: '/api', timeout: 3000 });
config.api = '/new-api'; // 错误!不能修改只读数据
const shallow = shallowReactive({ user: { name: '张三' } });
shallow.user.name = '李四'; // 不会触发更新!
const instance = markRaw(new ThirdPartyClass());
const state = reactive({ instance }); // instance 不会被代理
if (isReactive(state)) {
console.log(`${state} 是响应式对象`);
}
const raw = toRaw(state); // 获取未被代理的原始对象
这些工具函数让响应式系统更加灵活和强大。
readonly 会创建一个只读的响应式代理,任何修改操作都会失败,有以下适用场景:
const ReactiveFlags = {
IS_REACTIVE: '__v_isReactive',
IS_READONLY: '__v_isReadonly'
};
// 工具函数
function isObject(val) {
return val !== null && typeof val === 'object';
}
function isReactive(value) {
return !!(value && value[ReactiveFlags.IS_REACTIVE]);
}
function isReadonly(value) {
return !!(value && value[ReactiveFlags.IS_READONLY]);
}
// 只读处理器
const readonlyHandlers = {
get(target, key, receiver) {
// 处理特殊标记
if (key === ReactiveFlags.IS_REACTIVE) {
return false;
}
if (key === ReactiveFlags.IS_READONLY) {
return true;
}
const result = Reflect.get(target, key, receiver);
// 嵌套对象也变成只读
if (isObject(result)) {
return readonly(result);
}
return result;
},
set(target, key, value, receiver) {
return true; // 返回true表示操作"成功",但实际上没有修改
},
deleteProperty(target, key) {
return true; // 返回true表示操作"成功",但实际上没有删除
}
};
// 只读代理函数
function readonly(target) {
if (!isObject(target)) {
return target;
}
if (isReadonly(target)) {
return target;
}
return new Proxy(target, readonlyHandlers);
}
shallowReactive 会创建一个只对顶层属性进行响应式处理的代理,嵌套对象不会被代理,有以下适用场景:
const ReactiveFlags = {
IS_REACTIVE: '__v_isReactive',
IS_READONLY: '__v_isReadonly'
};
// 工具函数
function isObject(val) {
return val !== null && typeof val === 'object';
}
function isReactive(value) {
return !!(value && value[ReactiveFlags.IS_REACTIVE]);
}
function isReadonly(value) {
return !!(value && value[ReactiveFlags.IS_READONLY]);
}
// 只读处理器
const readonlyHandlers = {
get(target, key, receiver) {
// 处理特殊标记
if (key === ReactiveFlags.IS_REACTIVE) {
return false;
}
if (key === ReactiveFlags.IS_READONLY) {
return true;
}
const result = Reflect.get(target, key, receiver);
// 浅层:不代理嵌套对象
return result;
},
set(target, key, value, receiver) {
const result = Reflect.set(target, key, value, receiver);
return result;
}
};
// 浅层响应式函数
function shallowReactive(target) {
if (!isObject(target)) {
return target;
}
return new Proxy(target, shallowReactiveHandlers);
}
markRaw 会标记一个对象,使其永远不会被响应式代理,有以下适用场景:
// 定义原始标记
const RAW_MARK = '__v_skip';
// markRaw 函数
function markRaw(value) {
if (isObject(value)) {
Object.defineProperty(value, RAW_MARK, {
value: true,
enumerable: false,
configurable: true,
writable: false
});
}
return value;
}
// 检查是否应该跳过代理
function shouldSkip(value) {
return !!(value && value[RAW_MARK]);
}
// 修改reactive函数,支持跳过
function reactiveWithSkip(target) {
if (!isObject(target)) {
return target;
}
// 检查是否应该跳过
if (shouldSkip(target)) {
return target; // 直接返回原始对象,不进行代理
}
if (isReactive(target)) {
return target;
}
const proxy = new Proxy(target, {
get(target, key, receiver) {
if (key === ReactiveFlags.IS_REACTIVE) return true;
if (key === ReactiveFlags.RAW) return target;
const result = Reflect.get(target, key, receiver);
// 懒代理时也要检查skip
if (isObject(result) && !shouldSkip(result)) {
return reactiveWithSkip(result);
}
return result;
},
set(target, key, value, receiver) {
return Reflect.set(target, key, value, receiver);
}
});
return proxy;
}
// 完善ReactiveFlags
const ReactiveFlags = {
IS_REACTIVE: '__v_isReactive',
IS_READONLY: '__v_isReadonly',
IS_SHALLOW: '__v_isShallow',
RAW: '__v_raw'
};
// 判断函数
function isReactive(value) {
return !!(value && value[ReactiveFlags.IS_REACTIVE]);
}
function isReadonly(value) {
return !!(value && value[ReactiveFlags.IS_READONLY]);
}
function isShallow(value) {
return !!(value && value[ReactiveFlags.IS_SHALLOW]);
}
function isProxy(value) {
return isReactive(value) || isReadonly(value);
}
toRaw 会获取响应式代理背后的原始对象,有以下适用场景:
function toRaw(observed) {
const raw = observed && observed[ReactiveFlags.RAW];
return raw ? toRaw(raw) : observed;
}
// 定义所有标记
const ReactiveFlags = {
IS_REACTIVE: '__v_isReactive',
IS_READONLY: '__v_isReadonly',
IS_SHALLOW: '__v_isShallow',
RAW: '__v_raw',
SKIP: '__v_skip'
};
// 工具函数
function isObject(val) {
return val !== null && typeof val === 'object';
}
function isFunction(val) {
return typeof val === 'function';
}
// 类型判断
function isReactive(value) {
return !!(value && value[ReactiveFlags.IS_REACTIVE]);
}
function isReadonly(value) {
return !!(value && value[ReactiveFlags.IS_READONLY]);
}
function isShallow(value) {
return !!(value && value[ReactiveFlags.IS_SHALLOW]);
}
function isProxy(value) {
return isReactive(value) || isReadonly(value);
}
function isRef(value) {
return !!(value && value.__v_isRef === true);
}
// 原始对象获取
function toRaw(observed) {
const raw = observed && observed[ReactiveFlags.RAW];
return raw ? toRaw(raw) : observed;
}
// 跳过代理
const markRaw = (value) => {
if (isObject(value)) {
Object.defineProperty(value, ReactiveFlags.SKIP, {
value: true,
enumerable: false,
configurable: true,
writable: false
});
}
return value;
};
const shouldSkip = (value) => {
return !!(value && value[ReactiveFlags.SKIP]);
};
// 响应式处理器基类
class BaseReactiveHandler {
constructor(readonly = false, shallow = false) {
this.readonly = readonly;
this.shallow = shallow;
}
get(target, key, receiver) {
if (key === ReactiveFlags.IS_REACTIVE) {
return !this.readonly;
}
if (key === ReactiveFlags.IS_READONLY) {
return this.readonly;
}
if (key === ReactiveFlags.IS_SHALLOW) {
return this.shallow;
}
if (key === ReactiveFlags.RAW) {
return target;
}
const result = Reflect.get(target, key, receiver);
// 跳过代理检查
if (shouldSkip(result)) {
return result;
}
// 根据模式处理嵌套对象
if (isObject(result)) {
if (this.shallow) {
return result;
}
return this.readonly ? readonly(result) : reactive(result);
}
return result;
}
set(target, key, value, receiver) {
if (this.readonly) {
return true;
}
return Reflect.set(target, key, value, receiver);
}
deleteProperty(target, key) {
if (this.readonly) {
return true;
}
return Reflect.deleteProperty(target, key);
}
getType() {
if (this.readonly && this.shallow) return 'shallowReadonly';
if (this.readonly) return 'readonly';
if (this.shallow) return 'shallowReactive';
return 'reactive';
}
}
// 缓存Map
const reactiveMap = new WeakMap();
const readonlyMap = new WeakMap();
// 创建代理的通用函数
function createReactiveObject(target, handlers, proxyMap) {
if (!isObject(target)) {
return target;
}
if (target[ReactiveFlags.RAW] && !(proxyMap.has(target))) {
return target;
}
const existingProxy = proxyMap.get(target);
if (existingProxy) {
return existingProxy;
}
if (shouldSkip(target)) {
return target;
}
const proxy = new Proxy(target, handlers);
proxyMap.set(target, proxy);
return proxy;
}
// 主函数
function reactive(target) {
return createReactiveObject(
target,
new BaseReactiveHandler(false, false),
reactiveMap
);
}
// 只读函数
function readonly(target) {
return createReactiveObject(
target,
new BaseReactiveHandler(true, false),
readonlyMap
);
}
// 浅层函数
function shallowReactive(target) {
return createReactiveObject(
target,
new BaseReactiveHandler(false, true),
reactiveMap
);
}
// 浅层只读函数
function shallowReadonly(target) {
return createReactiveObject(
target,
new BaseReactiveHandler(true, true),
readonlyMap
);
}
本篇文章主要介绍了 reactive 的工具函数集,包含只读函数、浅层响应函数、跳过代理、类型判断等,对于文章中错误的地方或者有任何问题,欢迎在评论区留言讨论!