class ValueHolder {
#value;
get value() {return this.#value;}
set value(v) {this.#value = v;}
}
const holder = new ValueHolder();
function getValue1(x) {
return holder.value;
}
function wrappedValue1(x) { return getValue1(x); }
function getValue2(x, anyHolder=holder) {
return anyHolder.value;
}
function wrappedValue2(x) { return getValue2(x); }
function getValue3(x, anyHolder=holder) {
const propName = "value";
return anyHolder[propName];
}
function wrappedValue3(x) { return getValue3(x); }
function getValue4(x, anyHolder=holder, propName="value") {
return anyHolder[propName];
}
function wrappedValue4(x) { return getValue1(4); }
function benchmark(func) {
let x;
for (let i = 0; i < 1000000; i++) {
x = func(i);
}
return x;
}
benchmark(wrappedValue1)
benchmark(wrappedValue2)
benchmark(wrappedValue3)
benchmark(wrappedValue4)
--enable-precise-memory-info
flag.
Test case name | Result |
---|---|
Static object, static property | |
Dynamic object, static property | |
Dynamic object, const property | |
Dynamic object, dynamic property |
Test name | Executions per second |
---|---|
Static object, static property | 23.5 Ops/sec |
Dynamic object, static property | 21.3 Ops/sec |
Dynamic object, const property | 21.5 Ops/sec |
Dynamic object, dynamic property | 21.2 Ops/sec |
Let's break down the benchmark and explain what's being tested.
Benchmark Definition
The benchmark is measuring the speed of accessing class fields in different ways. The script definition includes four functions:
getValue1(x)
: Directly accesses the value
property on the holder
object.wrappedValue1(x)
: Wraps getValue1(x)
and calls it, which essentially does the same thing as getValue1(x)
.getValue2(x, anyHolder=holder)
: Accesses the value
property on an object named anyHolder
, defaulting to holder
if not provided.wrappedValue2(x)
: Wraps getValue2(x)
and calls it, similar to wrappedValue1(x)
.getValue3(x, anyHolder=holder)
: Accesses a property named value
on an object named anyHolder
, defaulting to holder
if not provided.wrappedValue3(x)
: Wraps getValue3(x)
and calls it, similar to wrappedValue2(x)
.getValue4(x, anyHolder=holder, propName="value")
: Accesses a property named propName
on an object named anyHolder
, defaulting to "value"
if not provided.wrappedValue4(x)
: Wraps getValue4(x)
and calls it, similar to wrappedValue1(x)
.What's being tested
The benchmark is measuring the speed of each function by executing them 1 million times in a loop. The results are displayed as the number of executions per second (ExecutionsPerSecond).
Options compared
There are four options being compared:
value
property (getValue1(x)
)wrappedValue1(x)
and wrappedValue4(x)
)value
on an object (getValue3(x)
)Pros and Cons
Here are the pros and cons of each approach:
value
property (getValue1(x)
):holder
is not a class).wrappedValue1(x)
and wrappedValue4(x)
):value
on an object (getValue3(x)
):Library
The benchmark uses a library called ES6 classes (ECMAScript 2015 Classes) to define the ValueHolder
class. This library provides a way to create classes in JavaScript, which can be useful for creating objects with complex behavior.
Special JS feature or syntax
None of the test cases use any special features or syntax beyond what's standard in ES6+ JavaScript.
Other alternatives
If you wanted to write this benchmark using alternative approaches, here are some options:
ValueHolder
class.Keep in mind that each alternative approach would have its own pros and cons, and may not be suitable for all use cases.