OOP vs PROCEDURAL (v3)

Revision 3 of this benchmark created on


Setup

function shuffle(array) {
  for (let i = (array.length - 1); i > 0; i -= 1) {
    const randomIndex = Math.floor(Math.random() * (i + 1));
    [array[i], array[randomIndex]] = [array[randomIndex], array[i]];
  }
}

const randomNumber = () => Math.floor(Math.random() * 10) + 1;

// === OO === //
class Shape2D {
  width
  height

  constructor(w, h=0) {
    this.width = w
    this.height = h
  }

  calculateArea() {
    throw new Error("calculateArea function is not implemented!")
  }
}

class Triangle extends Shape2D {
  calculateArea() {
    return (this.width * this.height) / 2
  }
}

class Square extends Shape2D {
  calculateArea() {
    return this.width * this.width
  }
}

class Circle extends Shape2D {
  calculateArea() {
    return Math.PI * this.width * this.width
  }
}

function sumAllShapes(shapes) {
  let total = 0
  for (const shape of shapes) {
    total += shape.calculateArea()
  }
  return total
}

const shapes = new Array(1000).fill(0).map(() => {
  const r = randomNumber()
  if (r < 3) return new Triangle(randomNumber(), randomNumber())
  if (r < 6) return new Square(randomNumber())
  else return new Circle(randomNumber())
})

// === Procedural === //
const triangleObj = { type: 'triangle', width: 10, height: 10 }
const squareObj = { type: 'square', width: 10 }

function calculateAreaTriangle(shape) {
  return (shape.width * shape.height) / 2
}

function calculateAreaSquare(shape) {
  return shape.side * shape.side
}

function calculateAreaCircle(shape) {
  return Math.PI * shape.radius * shape.radius
}

function sumAllShapesObj(shapes) {
  let total = 0
  for (const shape of shapes) {
    switch (shape.type) {
      case 'triangle':
        total += calculateAreaTriangle(shape)
        break
      case 'square':
        total += calculateAreaSquare(shape)
        break
      case 'circle':
        total += calculateAreaCircle(shape)
        break
    }
  }
  return total
}

const shapesObj = new Array(1000).fill(0).map(() => {
  const r = randomNumber()
  if (r < 3) return { type: 'triangle', width: randomNumber(), height: randomNumber() }
  if (r < 6) return { type: 'square', side: randomNumber() }
  else return {type: 'circle', radius: randomNumber()}
})

// === PROCEDURAL 2 === //
function sumAllShapesObj2(shapes) {
  let total = 0
  const l = shapes.length;
  for (let i=0; i < l; i++) {
  	const shape = shapes[i];
    switch (shape.type) {
      case 'triangle':
        total += (shape.width * shape.height) / 2;
        break
      case 'square':
        total += shape.side * shape.side
        break
      case 'circle':
        total += Math.PI * shape.radius * shape.radius
        break
    }
  }
  return total
}

const shapesObj2 = new Array(1000).fill(0).map(() => {
  const r = randomNumber()
  if (r < 3) return { type: 'triangle', width: randomNumber(), height: randomNumber() }
  if (r < 6) return { type: 'square', side: randomNumber() }
  else return {type: 'circle', radius: randomNumber()}
})

Test runner

Ready to run.

Testing in
TestOps/sec
OOP
shuffle(shapes)
sumAllShapes(shapes)
ready
PROCEDURAL
shuffle(shapesObj)
sumAllShapesObj(shapesObj)
ready
PROCEDURAL 2
shuffle(shapesObj2)
sumAllShapesObj2(shapesObj2)
ready

Revisions

You can edit these tests or add more tests to this page by appending /edit to the URL.