Javascript 类与函数返回对象

Javascript 类与函数返回对象,javascript,performance,class,es6-class,Javascript,Performance,Class,Es6 Class,我注意到有两种不同的方法可以有效地用JavaScript编写类(或类)。以简单计数器类为例: 一个实类(用作新计数器1()) 返回对象的函数(用作计数器2()) 我有很多代码可以用这两种风格中的任何一种来编写。我应该用哪一种 这是我的理解: Counter1可以与instanceof和继承一起使用,但更详细,没有真正的私有属性(例如count属性是公开的) Counter2更简洁,具有真正的私有方法/状态(函数中只有局部变量),但不能与instanceof和继承一起使用。它还为每个实例创建inc

我注意到有两种不同的方法可以有效地用JavaScript编写类(或类)。以简单计数器类为例:

一个实类(用作
新计数器1()

返回对象的函数(用作
计数器2()

我有很多代码可以用这两种风格中的任何一种来编写。我应该用哪一种

这是我的理解:

Counter1
可以与
instanceof
和继承一起使用,但更详细,没有真正的私有属性(例如
count
属性是公开的)

Counter2
更简洁,具有真正的私有方法/状态(函数中只有局部变量),但不能与
instanceof
和继承一起使用。它还为每个实例创建
inc
get
函数的新副本,这可能会影响性能?我不知道。

我推荐使用,因为

  • 类方法是

    类定义将“原型”中所有类成员方法的可枚举标志设置为false。这很好,因为如果我们对对象进行
    for..in
    ,我们通常不需要它的类方法

  • 类有一个默认值

    如果
    构造函数中没有
    构造函数
    ,则生成一个空函数,就像我们编写的一样

  • 总是上课

    类构造中的所有代码都将自动插入

  • 类还可以包括getter/setter
  • 我们还可以将方法分配给类函数,而不是它的“原型”


你可以更进一步。

两者都不应该对性能有很大影响。虽然类(
Counter1
在您的示例中)在技术上有稍好的性能,但只有当您每秒创建数千个类实例时(这可能是一个糟糕的设计选择),这一点才明显

至于其他优点,两者都有优点和缺点。FunFunFunction是学习JavaScript的一个很好的YouTube频道,也是我第一次学习工厂函数(
Counter
)的地方。频道所有者强烈支持使用
class
es

其中一个原因是,您无法从
this
关键字中获得与JS中实现类的方式一致的行为,因为它可能指的是调用函数的HTML元素,而不是您期望的对象

有关更多详细信息,请参阅

当然,这只是论点的一个方面,我确信也有使用
的论点。我更喜欢工厂功能,但最终你真的只需要选择一个,并与它滚动

我应该用哪一种

这个问题基本上是个人喜好的问题。OOP的真正信徒当然会采用
class
方法。一个明显的区别是,这将允许您子类化
Counter1
,但不清楚您为什么要这样做,甚至OOP爱好者也警告不要构建过于复杂的类层次结构

是的,第二种选择确实在每个实例上放置有问题的方法,而不是原型。是的,这确实会在理论上造成一些性能损失。但这并不是你需要担心的事情,除非你正在编写一个游戏,每一百万个对象有一个计数器


您可能正在使用某种transpiler或在本机ES6环境中运行。如果出于某种原因,您不是,那么您的第二个备选方案当然有一个优势,即它将在过去十年中的任何浏览器中运行(如果您将方法重写为
inc:function(){count++;}
)。

我将其放在一个jsperf页面中,以测试以任何一种方式创建新实例的速度:

以下是我的计算机上的结果(每秒创建新实例):

我不知道为什么带有
的Firefox的数量如此之高(希望它没有注意到代码没有任何效果,并且忽略了整个事情),或者为什么边缘数量如此之低

因此,至少在性能方面,真正的类要快得多,可能是因为它避免了为每个实例创建方法的新副本的开销

虽然冗长和缺少类的私有状态令人讨厌,但我认为性能优势更重要,但这取决于具体情况

编辑

我也对结果对象进行了测试调用
inc()
get()
,数字基本相同:

Test                   Chrome          Firefox         Edge
new Counter1();   215,352,342    2,072,278,834   23,570,036
Counter2();        14,309,836       35,564,201    9,801,748

尽管原型的属性仍然无法访问私有范围的变量,但带有函数构造函数的新关键字可能是最好的。(1)常规的旧对象文本可以包括getter和setter。(2) 在第二个示例中,“类方法”或“静态方法”可以很容易地直接放置在
计数器2
上。(3) 现在还不清楚为什么有一个默认构造函数在这里是相关的。(4) 请提供文档说明“类总是
使用strict
。我以为是ES6模块总是
使用strict
这个
关键字很棘手,特别是在混合方法和回调时,尽管有些静态类型系统(TypeScript,Flow)我接受这个答案,因为这是在两种情况都有可能的情况下,最有力的论据支持一种观点而不是另一种观点。
function Counter2(count = 0) {
  return {
    inc() {
      count++;
    },
    get() {
      return count;
    },
  };
}
Test                    Chrome           Firefox           Edge
new Counter1();    217,901,688     2,086,800,399     31,106,382
Counter2();         30,495,508        36,113,817      9,232,171
Test                   Chrome          Firefox         Edge
new Counter1();   215,352,342    2,072,278,834   23,570,036
Counter2();        14,309,836       35,564,201    9,801,748