简体   繁体   中英

How to refactor a complex JavaScript function?

I'm trying to refactor a bunch of methods that deconvolute an initial sequence into a final sequence. I can see three possible solutions, but I don't really understand what criteria I should use to choose between them.

To make the examples easier to digest, I've simplified the number of steps and the operations.

Option 1 - Constructor function, set the methods in the prototype

function Deconvoluter(initialValue) {
  this.initialValue = initialValue
  this.finalValue = null
}

Deconvoluter.prototype = {
  deconvolute() {
    this.firstStep()
    this.secondStep()
    return this.finalValue
  },

  firstStep() {
    this.finalValue = this.initialValue + 1
  },

  secondStep() {
    this.finalValue = this.finalValue + 10
  }
}

d = new Deconvoluter(0)
d.deconvolute() // 11

Option 2 - Regular function with private methods

function deconvolute2(initialValue) {
  this.initialValue = initialValue
  this.finalValue = null
  function firstStep() {
    this.finalValue = this.initialValue + 1
  }

  function secondStep() {
    this.finalValue = this.finalValue + 10
  }

  firstStep()
  secondStep()
  return this.finalValue
}

deconvolute2(0) // 11

Option 3 - Regular function with method properties

function deconvolute3(initialValue) {
  this.initialValue = initialValue
  this.finalValue = null
  this.firstStep = function() {
    this.finalValue = this.initialValue + 1
  }

  this.secondStep = function() {
    this.finalValue = this.finalValue + 10
  }

  this.firstStep()
  this.secondStep()
  return this.finalValue
}

deconvolute3(0) // 11

Is choosing between these options a matter of personal preference or is one option better than the others? If so, are there situations where the other two would work better?


Update

I've realized that the reason why I was drawn towards the third option is because I want to be able to access the intermediate steps. Would this then be a better implementation?

Option 4 - Decorator pattern

function ComplexCalculation(initialValue) {
  this.initialValue = initialValue

  setFirstStepCalculation(this)
  setSecondStepCalculation(this)
  setFinalValue(this)
}

function setFirstStepCalculation(calculation) {
  // much longer calculation goes here
  calculation.firstStepCalculation = calculation.initialValue + 1
}

function setSecondStepCalculation(calculation) {
  // much longer calculation goes here
  calculation.secondStepCalculation = calculation.firstStepCalculation + 10
}

function setFinalValue(calculation) {
  // much longer calculation goes here
  calculation.finalValue = calculation.secondStepCalculation + 100
}

cc = new ComplexCalculation(0)
cc.secondStepCalculation // 11
cc.finalValue // 111

There's really no value in using this in Option 2 and 3, and it's superfluous to initialize finalValue with null . I recommend this variant of option 2:

function deconvolute2(initialValue) {
    let finalValue;

    function firstStep() {
        finalValue = initialValue + 1
    }

    function secondStep() {
        finalValue = finalValue + 10
    }

    firstStep()
    secondStep()
    return finalValue
}

deconvolute2(0) // 11

Using the pattern of Option 1 makes sense if you want to have an object that holds a state (accessible through this and provides various methods to change this state.

So if, for example, you had not only a deconvolute method but also a convolute method, option 1 would be preferable.

The size and complexity of the firstStep and secondStep functions does not really matter.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM