如何在 Javascript 中生成 getter 和 setter?

发布于 2025-01-11 18:21:27 字数 1209 浏览 0 评论 0原文

我有以下非常重复的代码:

const flags = {
  get logged() {
    return localStorage.getItem("logged") === "true";
  },
  set logged(val: boolean) {
    if (val) {
      localStorage.setItem("logged", "true");
    } else {
      localStorage.removeItem("logged");
    }
  },
  get notificationsMuted() {
    return localStorage.getItem("notifications-muted") === "true"; 
  },
  set notificationsMuted(val: boolean) {
    if (val) {
      localStorage.setItem("notifications-muted", "true");
    } else {
      localStorage.removeItem("notifications-muted");
    }
  }
}

如您所见,每个标志类型的 getset 都是相同的,除了属性名称。我想做这样的事情:

function getter(prop: string) {
  return localStorage.getItem(prop) === "true";
}

function setter(prop: string, val: boolean) {
  if (val) {
    localStorage.setItem(prop, "true");
  } else {
    localStorage.removeItem(prop);
  }
}

const flags = {
  get logged: getter("logged")
  set logged: setter("logged")
  get notificationsMuted: getter("notifications-muted")
  set notificationsMuted: setter("notifications-muted")
}

但我不确定 Javascript / Typescript 是否支持这类事情。这样的事情可能吗?如果可能的话,如何实现?如果没有,有什么其他方法可以减少这里的重复吗?

I have the following code, which is very repetitious:

const flags = {
  get logged() {
    return localStorage.getItem("logged") === "true";
  },
  set logged(val: boolean) {
    if (val) {
      localStorage.setItem("logged", "true");
    } else {
      localStorage.removeItem("logged");
    }
  },
  get notificationsMuted() {
    return localStorage.getItem("notifications-muted") === "true"; 
  },
  set notificationsMuted(val: boolean) {
    if (val) {
      localStorage.setItem("notifications-muted", "true");
    } else {
      localStorage.removeItem("notifications-muted");
    }
  }
}

As you can see, the get and set for each flag type is identical, save for the property names. I would like to do something like this instead:

function getter(prop: string) {
  return localStorage.getItem(prop) === "true";
}

function setter(prop: string, val: boolean) {
  if (val) {
    localStorage.setItem(prop, "true");
  } else {
    localStorage.removeItem(prop);
  }
}

const flags = {
  get logged: getter("logged")
  set logged: setter("logged")
  get notificationsMuted: getter("notifications-muted")
  set notificationsMuted: setter("notifications-muted")
}

But I'm not sure if Javascript / Typescript has support for this sort of thing. Is such a thing possible, and if so, how? If not, is there any other way I can cut down on the repetition here?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

千纸鹤 2025-01-18 18:21:27

您可以将 代理获取设置 陷阱,使用 TS 类型只允许您想要处理的 props (TS 游乐场)):

interface Flags {
  logged: boolean,
  'notifications-muted': boolean;
}

type Prop = keyof Flags;

const handlers = {
  get(_: Flags, prop: Prop) {   
    return localStorage.getItem(prop) === "true";
  },
  
  set(_: Flags, prop: Prop, val: any) {
    if (val) {
      localStorage.setItem(prop, "true");
    } else {
      localStorage.removeItem(prop);
    }

    return true;
  }
};

const flags = new Proxy<Flags>({} as Flags, handlers);

You can use a proxy with get and set traps, use TS types to allow only props you wish to handle (TS playground)):

interface Flags {
  logged: boolean,
  'notifications-muted': boolean;
}

type Prop = keyof Flags;

const handlers = {
  get(_: Flags, prop: Prop) {   
    return localStorage.getItem(prop) === "true";
  },
  
  set(_: Flags, prop: Prop, val: any) {
    if (val) {
      localStorage.setItem(prop, "true");
    } else {
      localStorage.removeItem(prop);
    }

    return true;
  }
};

const flags = new Proxy<Flags>({} as Flags, handlers);
国粹 2025-01-18 18:21:27

您真正需要的只是将 Object.defineProperty 与具有 getset 属性的对象一起使用。或者,对于多个属性,使用Object.defineProperties一次性定义它们。

有助于代码组织的一种方法是不使用大量本地存储键,而是使用单个存储对象。

const props = ['logged', 'notificationsMuted'] as const;
const defaultStorage = Object.fromEntries(props.map(prop => [prop, false]));
const getStorage = () => JSON.parse(localStorage.getItem('settings') || JSON.stringify(defaultStorage));
const flags = Object.defineProperties(
    {},
    Object.fromEntries(
        props.map(
            prop => [
                prop,
                {
                    get: () => getStorage()[prop],
                    set: (newVal: boolean) => {
                        const store = getStorage();
                        store.prop = newVal;
                        localStorage.setItem('settings', JSON.stringify(store));
                    }
                }
            ]
        )
    )
) as Record<(typeof props)[number], boolean>;

All you really need is to use Object.defineProperty with an object with a get and set properties. Or, with multiple properties, use Object.defineProperties to define them all at once.

One approach which will help with code organization is to not use lots of local storage keys, but instead use a single object that gets stored.

const props = ['logged', 'notificationsMuted'] as const;
const defaultStorage = Object.fromEntries(props.map(prop => [prop, false]));
const getStorage = () => JSON.parse(localStorage.getItem('settings') || JSON.stringify(defaultStorage));
const flags = Object.defineProperties(
    {},
    Object.fromEntries(
        props.map(
            prop => [
                prop,
                {
                    get: () => getStorage()[prop],
                    set: (newVal: boolean) => {
                        const store = getStorage();
                        store.prop = newVal;
                        localStorage.setItem('settings', JSON.stringify(store));
                    }
                }
            ]
        )
    )
) as Record<(typeof props)[number], boolean>;
风和你 2025-01-18 18:21:27

这是我目前能想到的“最佳”解决方案。向任何能够对此提供改进的人开放:

function getter(prop: string): boolean {
  return localStorage.getItem(prop) === "true";
}

function setter(prop: string, val: boolean): void {
  if (val) {
    localStorage.setItem(prop, "true");
  } else {
    localStorage.removeItem(prop);
  }
}

const flags = {
  get logged() { return getter("logged") },
  set logged(val: boolean) { setter("logged", val) },
  get notificationsMuted() { return getter("notifications-muted"); },
  set notificationsMuted(val: boolean) { setter("notifications-muted", val); }
}

This is the current "best" solution I can come up with. Open to anyone who can provide an improvement over this:

function getter(prop: string): boolean {
  return localStorage.getItem(prop) === "true";
}

function setter(prop: string, val: boolean): void {
  if (val) {
    localStorage.setItem(prop, "true");
  } else {
    localStorage.removeItem(prop);
  }
}

const flags = {
  get logged() { return getter("logged") },
  set logged(val: boolean) { setter("logged", val) },
  get notificationsMuted() { return getter("notifications-muted"); },
  set notificationsMuted(val: boolean) { setter("notifications-muted", val); }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文