Class vs函数返回对象
我注意到有两种不同的方法可以有效地在JavaScript中编写一个类(或类的东西)。使用简单的计数器类为例:Class vs函数返回对象
一个真正的类(用作new Counter1()
)
class Counter1 {
constructor(count = 0) {
this.count = count;
}
inc() {
this.count++;
}
get() {
return this.count;
}
}
的函数返回一个对象(用作Counter2()
)
function Counter2(count = 0) {
return {
inc() {
count++;
},
get() {
return count;
},
};
}
我有很多的代码可以用这两种风格中的任何一种书写。我应该使用哪个?
这是我的理解:
Counter1
可以instanceof
和继承使用,但是更详细的,没有真正的私有属性(如count
属性暴露)。
Counter2
更简洁,具有真正的私有方法/状态(只是函数中的局部变量),但不能与instanceof
和继承一起使用。它还会为每个实例创建inc
和get
函数的新副本,这可能会影响性能?我不知道。
我把它放在一个jsperf页面在这里测试新的实例创建的速度,无论是风格:https://jsperf.com/class-vs-object-2
这里是我的计算机上的结果(每秒创建新实例):
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
我不知道为什么Firefox编号与class
是如此之高(希望它没有注意到代码没有效果,并且忽略了整个事情),或者为什么Edge数字如此之低。
因此,至少在性能方面,真实的类要快得多,可能是因为它避免了为每个实例创建方法的新副本的开销。
虽然类的冗长和缺乏私人状态令人讨厌,但我认为性能优势更重要,但它取决于具体情况。
编辑
我所做的结果对象的测试呼叫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
我接受这个答案是因为它是最强烈的论点,两种都可能的情况。 – Jesse
我建议使用classes,正因为如此,
-
类方法是non-enumerable。
类定义集枚举标志为假在“原型”所有类成员的方法。这很好,因为如果我们通过一个对象
for..in
,我们通常不希望它是类方法。 -
类有一个默认constructor() {}。
如果在
class
构造没有constructor
,然后一个空函数生成,一样的,如果我们写了constructor() {}。 -
类总是use strict。
类构造内的所有代码会自动在strict mode。
- 类也可能包括getters/setters。
-
我们也可以分配方法的类的功能,而不是它的“原型”。
您可以进一步here。
(1)一个普通的旧对象文字可以包括getter和setter。 (2)在第二个例子中,“类方法”或“静态方法”可以直接放在'Counter2'上。 (3)这里不清楚为什么有一个默认的构造函数。 (4)请提供关于“总是严格使用类”的说明文档,我认为这是ES6模块,总是使用“严格”。 – 2017-10-15 02:48:48
两者都不应该对性能有很大影响。虽然类(示例中的Counter1
)在技术上略有更好的性能,但如果您每秒创建数千个类的实例(这可能是一个糟糕的设计选择),这只是显而易见的。
至于其他优点,两者都有优点和缺点。 FunFunFunction是学习JavaScript的优秀YouTube频道,也是我第一次了解工厂功能的地方(Counter
)。渠道拥有者强烈支持这些使用class
es。
其中一个原因是你不能在this
关键字中使用类实现在JS中的方式获得一致的行为,因为它可能涉及类似于调用函数的HTML元素而不是你期待的目标。
有关更多详细信息,请参阅this video。
当然,这只是论证的一个方面,我相信也有使用class
的论点。我更喜欢工厂的功能,但最终你只需要选择一个,然后滚动。
您对“this”这个关键字的处理很棘手,特别是在混合方法和回调,虽然一些静态类型系统(TypeScript,Flow)可以帮助确保你做到了正确(尽管如此,他们经常会错误的) – Jesse
应该使用哪一个?
这个问题基本上是个人喜好的问题。真正的面向对象的信徒当然会采用class
的方法。一个明显的区别是,这将允许您继承Counter1
,但不清楚为什么你会这样做,甚至OOP爱好者都警告不要构建过于复杂的类层次结构。
是的,第二个选择确实将问题的方法放在每个实例上,而不是原型上。是的,这确实会造成一些理论上的性能损失。但是这不是你需要担心的事情,除非你正在为一百万个对象中的每一个写一个计数器。
假设您正在使用某种类型的编译器或在原生ES6环境中运行。如果由于某种原因,你不是,那么当然你的第二个选择的优点是它可以在任何浏览器中运行最近十年(如果你将方法改写为inc: function() { count++; }
)。
与功能构造新的关键字可能虽然原型的属性仍然无法访问私有作用域变量,但最好。 – user7951676