如何高效优雅地创建嵌套ES6类?
你担心的点完全没错——每次实例化Character时,在constructor里定义Info类确实会重复创建新的函数对象,这不仅浪费内存,而且完全没必要,因为所有Info实例的逻辑都是一致的。下面几种方案可以帮你实现高效的嵌套类:
方案1:将嵌套类挂载到原型上
把Info类定义在Character的原型上,这样所有Character实例都会共享同一个Info构造函数,不会重复创建:
class Character { bar() { const trial = new this.Info("Goofy", 2); alert(trial.name); } } // 把Info类挂载到Character的原型上 Character.prototype.Info = class Info { constructor(name, value) { this.name = name; this.value = value; } }; const test = new Character(); test.bar();
这种方式的好处是,所有Character实例的this.Info指向同一个类,避免了重复创建。外部也可以通过test.Info访问这个嵌套类。
方案2:使用静态属性定义嵌套类
如果希望Info类属于Character类本身,而不是实例,可以用静态属性来定义,这样只会创建一次,所有实例通过this.constructor.Info来引用:
class Character { // 静态属性,只初始化一次 static Info = class Info { constructor(name, value) { this.name = name; this.value = value; } }; bar() { const trial = new this.constructor.Info("Goofy", 2); alert(trial.name); } } const test = new Character(); test.bar(); // 外部也可以直接通过Character.Info访问 const infoInstance = new Character.Info("Mickey", 3);
这种方案更符合“嵌套类属于外部类”的语义,而且静态属性在类初始化时只会创建一次,效率很高。
方案3:闭包封装(完全隐藏嵌套类)
如果不想让Info类暴露给外部,只在Character内部使用,可以用IIFE(立即执行函数表达式)创建闭包,把Info封装起来:
const Character = (() => { // 只创建一次的Info类,外部无法访问 class Info { constructor(name, value) { this.name = name; this.value = value; } } return class Character { bar() { const trial = new Info("Goofy", 2); alert(trial.name); } }; })(); const test = new Character(); test.bar(); // 外部无法访问Info类,比如new test.Info()会报错
这种方案既保证了Info只创建一次,又实现了完全的封装,外部无法直接访问嵌套类,适合需要隐藏内部实现的场景。
为什么原来的写法效率低?
在Character的constructor里定义Info类,意味着每次调用new Character()时,都会重新定义一遍Info构造函数及其原型方法。每个Character实例的this.Info都是一个全新的函数对象,它们的逻辑完全相同,但占用了额外的内存,这显然是不必要的开销。
上面的三种方案都解决了这个问题,让Info类只被创建一次,所有Character实例共享同一个类,既节省内存又保持了代码的清晰性。
内容的提问来源于stack exchange,提问作者memememe

