【问题标题】:Class static getter which returns class in Javascript在Javascript中返回类的类静态getter
【发布时间】:2017-12-05 17:49:04
【问题描述】:

我有一些代码:

//Main class
class Tools { 

  //Subclass implemented by static getter 
  static get SUPPORTED_UNITS () {
    return class {  
      //Another one
      static get Size () {
        return class {
          //Some data (constants in my case)
        };
      }
    };
  }
}

我想像Tools.SUPPORTED_UNITS.Size 一样使用它,并且我想收到一些数据作为它的结果。 我使用 WebStorm 编写 JavaScript 代码,所以当我尝试使用它时它会显示给我。

我不太清楚,也许我只是还没有对我的 WebStorm 进行一些设置,但是.. 我需要做的是我可以使用像 Class.Subclass.SubClassMethod/SubSubclass 这样的构造。

我需要那个:

  • 这不是方法
  • 它是静态的
  • 它是不可变的(没有 Object.freeze 或类似的东西) - 所以我不能通过输入 Class.Subclass = foo; 来更改我的 Class.Subclass
  • 它由 IDE 编制索引 - 所以我从 IDE 获得了一些帮助(比如我输入 Class.Su 而她建议使用 Class.Subclass

在 ES6 和 WebStorm 中是真的吗?或者也许我必须使用 ES7 和 Babel 或类似的东西?

附:该代码工作,但我需要来自 IDE 的建议,否则它将像地狱一样。

【问题讨论】:

  • 由于代码是可行的并且没有使用 ES2016+ 的特性,你可以确定它是正确的 ES6,并且问题是特定于 IDE 的。代码没有解释为什么类应该被定义在inside一个方法中,这可能会导致XY问题。
  • 如果只实现静态方法,请不要使用类。请改用普通对象:const Tools = {SUPPORTED_UNITS: {Size: {}}}。如果需要,您也可以在对象上定义 getter。我建议阅读eloquentjavascript.net/04_data.html。此外,您实现的不是“子类”。子类通常是扩展基类的类。
  • @estus 我认为需要一个子类来使用不允许更改内部数据的 getter。也许我想错了(这很正常,因为我刚刚开始深入)。那么我需要如何编写我的类来使用不可变的静态数据呢?示例:Tools.SUPPORTED_UNITS.Size不能改变任何东西(写Tools.SUPPORTED_UNITS = foo)。谢谢
  • @FelixKling 感谢您的评论。所以你提议使用 const 对象来替换某种静态类? P.S. 当然是嵌套类,抱歉...
  • 是的,那是正确的。添加 Object.freeze 品尝。您还可以重新考虑为什么您需要它是只读的。如果它真的没有任何帮助并导致额外的代码量,那就是奥卡姆剃刀的主题。

标签: javascript ecmascript-6 webstorm es6-class


【解决方案1】:

遵循@estus 和@Felix Kling 的建议...(可能在此处被歪曲)

const TOOLS = {
    get SUPPORTED_UNITS() {
        return {
            get SIZE() {
                return {
                    get Bar() { 
                        return 1;
                    }
                }
            }
        }
    }
};
console.log(TOOLS.SUPPORTED_UNITS.SIZE.Bar) // 1;

TOOLS.SUPPORTED_UNITS.SIZE = "Hello";
// TOOLS.SUPPORTED_UNITS.SIZE = "Hello";
//                            ^
// TypeError: Cannot set property SIZE of #<Object> which has only a getter

这可行,但正如@bergi 所说,它会在每次查找中创建一个新对象:

console.log(TOOLS.SUPPORTED_UNITS === TOOLS.SUPPORTED_UNITS); // false

是的……

仍然使用 getter 的替代方法是将所有这些对象封装在 IIFE 中:

const TOOLS = (function () {
    const SIZE = {
        get Bar() { return 1; }
    }
    const SUPPORTED_UNITS = {
        get SIZE() {
            return SIZE;
        }
    }
    return {
        get SUPPORTED_UNITS() {
            return SUPPORTED_UNITS;
        }
    }
}());

console.log(TOOLS.SUPPORTED_UNITS.SIZE.Bar === TOOLS.SUPPORTED_UNITS.SIZE.Bar); // true
console.log(TOOLS.SUPPORTED_UNITS.SIZE === TOOLS.SUPPORTED_UNITS.SIZE);  // true
console.log(TOOLS === TOOLS); // true

TOOLS.SUPPORTED_UNITS = "hello"; // still throws an error

第三次更新:

第二个示例解决了与每次查找创建新对象相关的问题,但它也没有考虑到对每个嵌套属性的访问会导致函数调用以重新评估不应更改的内容:

//A naive measurement:
for(let counter = 0; counter < 5; counter++) {
    let start = Date.now();    
    for(let i = 0; i < 200000; i++){
        let somevar = Tools.SUPPORT_UNITS.SIZE;
    }
    let end = Date.now();
    console.log(`Elapsed using nested getters: ${end - start}ms.`);
}
// Something like:
/** Elapsed using nested getters: 20ms.
 * Elapsed using nested getters: 14ms.
 * Elapsed using nested getters: 9ms.
 * Elapsed using nested getters: 10ms.
 * Elapsed using nested getters: 10ms.
 *
 // While the same as ordinary properties:
 * Elapsed ordinary properties: 2ms.
 * Elapsed ordinary properties: 5ms.
 * Elapsed ordinary properties: 1ms.
 * Elapsed ordinary properties: 0ms.
 * Elapsed ordinary properties: 0ms.
 */

因此,如果在可预见的将来运行 200000 次循环,则最好在使用此方法之前检查替代方案。

【讨论】:

  • 你肯定不想使用吸气剂。他们会在每次访问时重新创建对象。
  • @betadeveloper 您对使用 deepFreeze 功能有何看法?制作一个对象,对其进行深度冻结 => 提供静态对象之类的东西
  • 标准 Object.freeze 的结果是一个浅冻结对象,你必须自己实现一个 deepFreeze 或找到一个库。此外,最好检查 MDN 页面中的警告:“要使对象保持不变,请递归冻结对象类型的每个属性(深度冻结)。**根据您的具体情况逐个使用该模式当你知道对象在参考图中不包含循环时进行设计,否则将触发无限循环。**
猜你喜欢
  • 1970-01-01
  • 2017-05-18
  • 1970-01-01
  • 2014-01-22
  • 2012-07-24
  • 1970-01-01
  • 2011-09-09
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多