使用Proxy怎么实现一个safeGet函数?

  // 设计一个函数 safeGet,可以对任意对象进行处理使其满足
  const x = safeGet({
    a: 'hello',
    b: { d: 'world' },
    c: [-100, 200, -300],
  });
  
  x.a() === 'hello'
  x.b.d() === 'world'
  x.c[0]() === -100
  x.c[100]() === undefined
  x.c[100](1234) === 1234
  x.c.map((e) => e()) === [-100, 200, -300]
  x.d.e() === undefined
  x.d.e('optional default value') === 'optional default value'
  x.y.z.a.b.c.d.e.f.g.h.i.j.k() === undefined
  
  function safeGet(data) {
      // write code here
  }
阅读 3.2k
3 个回答
function safeGet(data) {
    return new Proxy(() => {}, {
        get(target, prop) {
            if (data !== undefined && prop in data) {
                const value = data[prop];
                if (typeof value === 'function' && prop !== 'constructor') {
                    return value.bind(data);
                }
                return safeGet(value);
            } else {
                return safeGet(undefined);
            }
        },
        apply(target, thisArg, args) {
            if (data !== undefined) {
                return data;
            }
            if (args.length > 0) {
                return args[0];
            }
            return undefined;
        }
    });
}

// 测试
const x = safeGet({
    a: 'hello',
    b: { d: 'world' },
    c: [-100, 200, -300],
});

console.log(x.a() === 'hello');
console.log(x.b.d() === 'world');
console.log(x.c[0]() === -100);
console.log(x.c[100]() === undefined);
console.log(x.c[100](1234) === 1234);
console.log(JSON.stringify(x.c.map((e) => e())) === JSON.stringify([-100, 200, -300]));
console.log(x.d.e() === undefined);
console.log(x.d.e('optional default value') === 'optional default value');
console.log(x.y.z.a.b.c.d.e.f.g.h.i.j.k() === undefined);

不太理解 safeGet 的应用场景?
有没有一种可能, ?. 可选链操作符 比较方便?
var x = { a: { b: 1 } };

console.log(x?.a) // { b: 1 }
console.log(x?.a.b.c) // undefined

PS: 需要优化兼容好像是 ES9 还是 ES10 的不记得了
PS:需要优化格式化插件,可能会被格式转成 x ? .a.b.c

新手上路,请多包涵

代码:

const isObject = (obj: any) => obj && typeof obj === 'object';
const hasKey = (obj: any, key: string | symbol) => key in obj;

const Undefined: any = new Proxy(() => {}, {
    get: function(target, name){
        return Undefined;
    },
    apply: function(target, p, newValue) {
        if (newValue.length >= 1) {
            return newValue[0];
        }
        return undefined;
    }
});

export function safeGet(data: any): any {
    // write code here
    return new Proxy(data, {
        get: function(target, name){
            return hasKey(target, name)
                ? isObject(target[name])
                    ? safeGet(target[name])
                    : new Proxy(() => {}, {
                        get: () => target[name],
                        apply: (t, p, args) => {
                            if (typeof args[0] === 'function' && name === 'map') {
                                return target.map((v: any) => {
                                    return new Proxy(() => {}, {
                                        apply: () => v,
                                    });
                                }).map(args[0]);
                            }
                            return target[name];
                        }
                    })
                : Undefined;
        },
    });
}
  

下面是 jest 测试用例:

import { safeGet } from "./safeget"; 

describe('test safeget', () => {
    let safeObj: any;
    beforeAll(() => {
        safeObj = safeGet({
            a: 'hello',
            b: { d: 'world' },
            c: [-100, 200, -300],
        });
    });
    test('add get', () => {
        expect(safeObj.a()).toBe('hello');
        expect(safeObj.c[0]()).toBe(-100);

        expect(safeObj.c[100]()).toBeUndefined();
        expect(safeObj.c[100](1234)).toBe(1234);
        expect(safeObj.d.e()).toBeUndefined();
        expect(safeObj.d.e('optional default value')).toBe('optional default value');
        expect(safeObj.y.z.a.b.c.d.e.f.g.h.i.j.k()).toBeUndefined();
    });
    test('add iterator', () => {
        expect(safeObj.c.map((e: any) => e())).toStrictEqual([-100, 200, -300]);
    });
});

本地测没啥问题,但是map那实现的比较挫。
image.png

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题