美文网首页JavaScript 进阶营
优雅的 JavaScript 之 编写优雅的 Settings

优雅的 JavaScript 之 编写优雅的 Settings

作者: 一半晴天 | 来源:发表于2018-06-04 20:07 被阅读80次

    写应用时经常需要用到保存一些用户设置的功能。怎么样在 JavaScript 写出优雅的代码出来呢?下面我将一步步实现出我认为比较优雅的代码。

    初始阶段

    假设我们一开始封装了如下代码。其中 storage 你可以当作是 LocalStorage
    或者就当作小程序中的 storage。总而言之当作一个 Key Value 存储对象。

    interface IStorage {
      [key: string]: any;
    }
    
    const storage: IStorage = {};
    function getByKey(key: string): any {
      return storage[key];
    }
    
    function setByKey(key: string, value: any) {
      if (typeof value === "undefined") {
        return;
      }
      storage[key] = value;
    }
    

    添加我们编好设置代码

    在上面的代码的基础上,此时我们需要记录用户的 username,autoLogin 两个属性。 然后我们写出如下代码。

    
    function getUsername() {
      return getByKey("username");
    }
    
    function setUsername(username: string) {
      setByKey("username", username);
    }
    
    function getAutoLogin() {
      return getByKey("autoLogin");
    }
    
    function setAutoLogin(autoLogin: boolean) {
      setByKey("autoLogin", autoLogin);
    }
    

    使用的时候我们这样使用:

    const username = getUsername();
      setUsername("banxi");
      const autoLogin = getAutoLogin();
      setAutoLogin(true);
    

    这样的话,用起来中规中矩,没毛病。 只是觉得不太 cool.

    开始优雅起来

    我们可以利用 gettersetterSettings 类的使用者优雅起来。我们以其中的 username 属性为例。引入 Settings

    class Settings {
      public get username(): string {
        return getByKey("username");
      }
    
      public set username(value: string) {
        setByKey("username", value);
      }
    }
    
    const settings = new Settings();
    

    然后就可以向下面这样很自然的使用了。是不是看起来优雅多了?

    settings.username = "banxi";
     const username = settings.username;
    

    上面的使用方式是优雅了,但是写的 gettersetter 看起来还是有比较多的冗余的东西。比如上面的实现中 "username" 字符串使用了两次,另外gettersetterusername 名称也出现了两次。看起来确实比较冗余。

    优雅,可以更优雅一点

    为了简化 Settings 类中属性的声明,我们可以引入 @decorator ,即装饰器。
    增加一个名为 asSetting 的装饰器

    /**
     * @param defaultValue 设置项的默认值
     * @param key 自定义其他的 key 值, 自定义 key 值可以避免代码 ugly 之后,属性名改变,然后
     *  读取不到对应值。
     */
    function asSetting(defaultValue: any, key?: string) {
      return function(
        target: any,
        propertyKey: string,
        descriptor: PropertyDecorator
      ) {
        const pkey = key || propertyKey;
        Object.defineProperty(target, pkey, {
          get: function() {
            const ret = getByKey(propertyKey);
            if (typeof ret === "undefined") {
              return defaultValue;
            } else {
              return ret;
            }
          },
    
          set: function(value) {
            setByKey(propertyKey, value);
          }
        });
      } as any;
    }
    

    然后我们的 Settings 类就可以改写成这样了。

    
    class Settings {
      @asSetting(false)
      autoLogin: boolean;
    
      @asSetting(null)
      username: string;
    
      @asSetting(16, "userAge")
      age: number;
    }
    const settings = new Settings();
    

    这样使用:

    function main() {
      console.log("default age expected 16 ,actual: ", settings.age);
      settings.username = "banxi";
      const username = settings.username;
      console.info("username :", username);
      settings.age = 19;
      settings.autoLogin = true;
      console.info("current settings:", storage);
    }
    

    相关文章

      网友评论

        本文标题:优雅的 JavaScript 之 编写优雅的 Settings

        本文链接:https://www.haomeiwen.com/subject/kbnysftx.html