实现vue3 readonly 操作

//主入口函数
const readonlyMap = new WeakMap();

const objectToString = Object.prototype.toString;

const readonlyGet =  createGetter(true);

function createGetter(isReadonly = false, shallow = false) {
    return function get(target, key, receiver) {
        if (key === "__v_isReactive" /* IS_REACTIVE */) {
            return !isReadonly;
        }
        else if (key === "__v_isReadonly" /* IS_READONLY */) {
            return isReadonly;
        }
        else if (key === "__v_raw" /* RAW */ &&
            receiver ===
                (isReadonly
                    ? shallow
                        ? shallowReadonlyMap
                        : readonlyMap
                    : shallow
                        ? shallowReactiveMap
                        : reactiveMap).get(target)) {
            return target;
        }
        const targetIsArray = isArray(target);
        if (!isReadonly && targetIsArray && hasOwn(arrayInstrumentations, key)) {
            return Reflect.get(arrayInstrumentations, key, receiver);
        }
        const res = Reflect.get(target, key, receiver);
        if (isSymbol(key) ? builtInSymbols.has(key) : isNonTrackableKeys(key)) {
            return res;
        }
        if (!isReadonly) {
            track(target, "get" /* GET */, key);
        }
        if (shallow) {
            return res;
        }
        if (isRef(res)) {
            // ref unwrapping - does not apply for Array + integer key.
            const shouldUnwrap = !targetIsArray || !isIntegerKey(key);
            return shouldUnwrap ? res.value : res;
        }
        if (isObject(res)) {
            // Convert returned value into a proxy as well. we do the isObject check
            // here to avoid invalid value warning. Also need to lazy access readonly
            // and reactive here to avoid circular dependency.
            return isReadonly ? readonly(res) : reactive(res);
        }
        return res;
    };
}
const readonlyHandlers = {
    get: readonlyGet,

    //下面两个函数只要被执行,就会弹出报错,所以我们只需要重点看第一个get函数
    set(target, key) {
        {
            console.warn(`Set operation on key "${String(key)}" failed: target is readonly.`, target);
        }
        return true;
    },
    deleteProperty(target, key) {
        {
            console.warn(`Delete operation on key "${String(key)}" failed: target is readonly.`, target);
        }
        return true;
    }
};

//主入口函数
function readonly(target) {
    return createReactiveObject(target, true, readonlyHandlers, readonlyMap);
}
//类型判断函数

const isObject = (val) => val !== null && typeof val === 'object';
const isArray = Array.isArray;
const isSymbol = (val) => typeof val === 'symbol'; 

function createReactiveObject(target, isReadonly, baseHandlers, proxyMap) {
    //传入isReadonly 值为true,判断传入的值是否为除Null 以外的Object对象,如果不是的话就会弹出错误,
    if (!isObject(target)) {
        {
            console.warn(`value cannot be made reactive: ${String(target)}`);
        }
        return target;
    }
    // target is already a Proxy, return it.
    // exception: calling readonly() on a reactive object
    // 这些条件都满足的话说明传入的已经是一个reactive对象了 ,直接return 返回即可
    if (target["__v_raw" /* RAW */] &&!(isReadonly && target["__v_isReactive" /* IS_REACTIVE */])) {
        return target;
    }
    
    // 初始化时proxyMap 为空 
    console.log(proxyMap,'proxymap')    //WeakMap { <items unknown> } proxymap 
    const existingProxy = proxyMap.get(target);   //获取到的值为undefined 
    if (existingProxy) {
        return existingProxy;
    }
    // only a whitelist of value types can be observed.
    const targetType = getTargetType(target);
    if (targetType === 0 /* INVALID */) {
        return target;
    }
    console.log(targetType,'targetType')
    const proxy = new Proxy(target, baseHandlers);
    proxyMap.set(target, proxy);
    return proxy;
}

function getTargetType(value) {
    return value["__v_skip" /* SKIP */] || !Object.isExtensible(value)
        ? 0 /* INVALID */
        : targetTypeMap(toRawType(value));
}
function targetTypeMap(rawType) {
    switch (rawType) {
        case 'Object':
        case 'Array':
            return 1 /* COMMON */;
        case 'Map':
        case 'Set':
        case 'WeakMap':
        case 'WeakSet':
            return 2 /* COLLECTION */;
        default:
            return 0 /* INVALID */;
    }
}
const toRawType = (value) => {
    // extract "RawType" from strings like "[object RawType]"
    return toTypeString(value).slice(8, -1);
};
const toTypeString = (value) => objectToString.call(value);

var result = readonly({a:2})
console.log(result)

控制台输出

//主入口函数

const readonlyMap = new WeakMap();

const readonlyCollectionHandlers = {

    get: createInstrumentationGetter(true, false)

};

function createInstrumentationGetter(isReadonly, shallow) {

    const instrumentations = shallow

        ? isReadonly

            ? shallowReadonlyInstrumentations

            : shallowInstrumentations

        : isReadonly

            ? readonlyInstrumentations

            : mutableInstrumentations;

    return (target, key, receiver) => {

        if (key === "__v_isReactive" /* IS_REACTIVE */) {

            return !isReadonly;

        }

        else if (key === "__v_isReadonly" /* IS_READONLY */) {

            return isReadonly;

        }

        else if (key === "__v_raw" /* RAW */) {

            return target;

        }

        return Reflect.get(hasOwn(instrumentations, key) && key in target

            ? instrumentations

            : target, key, receiver);

    };

}

const readonlyGet =  createGetter(true);



function createGetter(isReadonly = false, shallow = false) {

    //问题,proxy实现拦截

    return function get(target, key, receiver) {

        if (key === "__v_isReactive" /* IS_REACTIVE */) {

            return !isReadonly;

        }

        else if (key === "__v_isReadonly" /* IS_READONLY */) {

            return isReadonly;

        }

        else if (key === "__v_raw" /* RAW */ &&

            receiver ===

                (isReadonly

                    ? shallow

                        ? shallowReadonlyMap

                        : readonlyMap

                    : shallow

                        ? shallowReactiveMap

                        : reactiveMap).get(target)) {

            return target;

        }

        const targetIsArray = isArray(target);

        if (!isReadonly && targetIsArray && hasOwn(arrayInstrumentations, key)) {

            return Reflect.get(arrayInstrumentations, key, receiver);

        }

        const res = Reflect.get(target, key, receiver);

        if (isSymbol(key) ? builtInSymbols.has(key) : isNonTrackableKeys(key)) {

            return res;

        }

        if (!isReadonly) {

            track(target, "get" /* GET */, key);

        }

        if (shallow) {

            return res;

        }

        if (isRef(res)) {

            // ref unwrapping - does not apply for Array + integer key.

            const shouldUnwrap = !targetIsArray || !isIntegerKey(key);

            return shouldUnwrap ? res.value : res;

        }

        if (isObject(res)) {

            // Convert returned value into a proxy as well. we do the isObject check

            // here to avoid invalid value warning. Also need to lazy access readonly

            // and reactive here to avoid circular dependency.

            return isReadonly ? readonly(res) : reactive(res);

        }

        return res;

    };

}

const readonlyHandlers = {

    get: readonlyGet,



    //下面两个函数只要被执行,就会弹出报错,所以我们只需要重点看第一个get函数

    set(target, key) {

        {

            console.warn(`Set operation on key "${String(key)}" failed: target is readonly.`, target);

        }

        return true;

    },

    deleteProperty(target, key) {

        {

            console.warn(`Delete operation on key "${String(key)}" failed: target is readonly.`, target);

        }

        return true;

    }

};



//主入口函数

function readonly(target) {

    return createReactiveObject(target, true, readonlyHandlers, readonlyCollectionHandlers, readonlyMap);

}

//类型判断函数



const isObject = (val) => val !== null && typeof val === 'object';

const isArray = Array.isArray;

const isSymbol = (val) => typeof val === 'symbol';





function createReactiveObject(target, isReadonly, baseHandlers, collectionHandlers, proxyMap) {

    //传入isReadonly 值为true,判断传入的值是否为除Null 以外的Object对象,如果不是的话就会弹出错误,

    if (!isObject(target)) {

        {

            console.warn(`value cannot be made reactive: ${String(target)}`);

        }

        return target;

    }

    // target is already a Proxy, return it.

    // exception: calling readonly() on a reactive object

    // 这些条件都满足的话说明传入的已经是一个reactive对象了 ,直接return 返回即可

    if (target["__v_raw" /* RAW */] &&!(isReadonly && target["__v_isReactive" /* IS_REACTIVE */])) {

        return target;

    }

   

    // 初始化时proxyMap 为空



    const existingProxy = proxyMap.get(target);

    if (existingProxy) {

        return existingProxy;

    }

    // only a whitelist of value types can be observed.



    //

    const targetType = getTargetType(target);   //判断传入的数据类型,如果是Object类型数据 返回值一般为1

    if (targetType === 0 /* INVALID */) {

        这里是因为数据类型不满足要求,所以直接把数据返回了出去

        return target;

    }



    //这里一般调用传入的handlers是 baseHandlers  这里调用的传入的是readonlyHandlers 所以转到这个readonlyHandlers继续阅读

    const proxy = new Proxy(target, targetType === 2 /* COLLECTION */ ? collectionHandlers : baseHandlers);

    proxyMap.set(target, proxy);

    return proxy;

}



const objectToString = Object.prototype.toString;

function getTargetType(value) {

    //初始化的时候值为false 返回的三元表达式后半部分调用了targetTypeMap()函数,传入了另一个函数toRawType()并且给它传入value

    //值

    return value["__v_skip" /* SKIP */] || !Object.isExtensible(value)    

        ? 0 /* INVALID */

        : targetTypeMap(toRawType(value));

}

function targetTypeMap(rawType) {

    //这里进行判断 如果是传入的类型是'Object'和'Array' 返回1

    //传入数据类型 为 'Map' ,'Set','WeakSet' ,'WeakMap' 返回2

    //其他的数据类型返回为 0

  switch (rawType) {

      case 'Object':

      case 'Array':

          return 1 /* COMMON */;

      case 'Map':

      case 'Set':

      case 'WeakMap':

      case 'WeakSet':

          return 2 /* COLLECTION */;

      default:

          return 0 /* INVALID */;

  }

}

const toRawType = (value) => {

  // extract "RawType" from strings like "[object RawType]"

  //提取Object.prototype.string.call(value) 的数据类型

  return toTypeString(value).slice(8, -1);

};



const toTypeString = (value) => objectToString.call(value);

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值