class 上的函数包装器性能基准测试与仅构造函数调用调用和 HaveSameMap

Performance benchmarking of function wrapper over class vs only constructor call invocation and HaveSameMap

我用 CODE A 和 CODE B 做了一些性能测量,想知道为什么 V8 输出如此。

代码A

const makePoint = () => {
  class Point {
    constructor(x, y) {
      this.x = x;
      this.y = y;
    }
  }

  return new Point(1, 2);
}

const a = makePoint();
const b = makePoint();

console.log(%HaveSameMap(a, b)); // false

第一个问题,为什么世界上HaveSameMap returns false。我相信 a 和 b 都具有相同的形状并经历相同的过程。那么为什么他们会不同呢?

代码B

class Point {
    constructor(x, y) {
      this.x = x;
      this.y = y;
    }
 }
 var a = new Point();
 var b = new Point();

第二个问题 - 比较两者的执行时间有很大差异。我只想了解 V8 类型系统的底层。为什么会这样。调用 new Point() 与在 makePoint() 函数中返回它。这是怎么回事?

更新 - 测试方法

我正在通过外部包进行测试

我的测试代码看起来像

const { performance } = require('perf_hooks');

performance.mark('start');

while (iterations--) {
  makePoint();
}

performance.mark('end');

performance.measure('My Special Benchmark', 'start', 'end');

您在每次调用 makePoint 时都会创建一个新的 Point class。当您直接 return class:

时,这可能会变得更加明显
const makePoint = (x, y) => {
  class Point {...};
  return Point;
}

每次计算 class 文字时都会创建一个 class。在 class 定义之前添加 console.log 时,您可以稍微看到这种情况的发生。在您的情况下,每次都会进行评估。

同样,每次创建一个新的 class 比简单地重新使用相同的 class 成本更高。 V8 必须创建大量内部数据结构来支持快速创建实例。一次使用 class 就可以击败这种非常常见的模式,即您看到的减速。

在您的第一个片段中,您不仅在 makePoint 中创建了实例,而且还在 class Point 本身中创建了实例。每次你调用 makePoint(),你都会创建一个新的 class:

console.log(makePoint().constructor === makePoint().constructor) // false

我想你正在寻找

class Point {
  constructor(x, y) {
    this.x = x;
    this.y = y;
  }
}
const makePoint = () => new Point(1, 2);
const a = makePoint();
const b = makePoint();

console.log(%HaveSameMap(a, b)); // true
console.log(a.constructor == b.constructor, a.constructor == Point); // true, true