Home > Software design >  Typescript/Javascript Call Method Reference with arguments
Typescript/Javascript Call Method Reference with arguments

Time:11-22

I have a bulk operation that operates on a 2 dimensional array. It shall call a given method "func" on each element in the array:

function forEachMatrixElement(matrix: Complex[][], func: Function): Complex[][] {
  let matrixResult: Complex[][] = new Array(countRows(matrix)).fill(false).map(() => new Array(countCols(matrix)).fill(false)); // Creates a result 2D-Matrix
  for (let row = 0; row < countRows(matrix); row  ) {
    for (let col = 0; col < countCols(matrix); col  ) {
      matrixResult[row][col] = func.call(matrix[row][col]); // Call the given method
    }
  }
  return matrixResult;
}

I have two functions that I want to delegate to this method: This one takes no additional arguments and works fine:

export function conjugateMatrix(matrix: Complex[][]): Complex[][] {
  return forEachMatrixElement(matrix, Complex.prototype.conjugate);
}

This one takes an additional argument (a scalar). But I don't know how to add this argument to this method reference on the prototype:

export function multiplyMatrixScalar(matrix: Complex[][], scalar: Complex): Complex[][] {
  return forEachMatrixElement(matrix, Complex.prototype.mul); // TODO Call with scalar
}

CodePudding user response:

Reaching into the prototype and manipulating the value of this with call() is usually a bad idea. This can be made simpler.

Instead, the forEachMatrixElement should simply take a function that accepts a Complex instance, and the caller can decide what that function does and how to apply its arguments.

For example:

function forEachMatrixElement(
  matrix: Complex[][],
  func: (complex: Complex) => Complex // Changed this function type
): Complex[][] {
  let matrixResult: Complex[][] = new Array(countRows(matrix)).fill(false).map(() => new Array(countCols(matrix)).fill(false));
  for (let row = 0; row < countRows(matrix); row  ) {
    for (let col = 0; col < countCols(matrix); col  ) {
     
      // just invoke the function like any other. No .call()
      matrixResult[row][col] = func(matrix[row][col]); 
      
    }
  }
  return matrixResult;
}

Now the functions that call this can simply be:

export function conjugateMatrix(matrix: Complex[][]): Complex[][] {
  return forEachMatrixElement(matrix, (c) => c.conjugate());
}

export function multiplyMatrixScalar(matrix: Complex[][], scalar: Complex): Complex[][] {
  return forEachMatrixElement(matrix, (c) => c.mul(scalar));
}

See Playground

CodePudding user response:

Could you just create a new function in multiplyMatrixScalar?

Something like:

export function multiplyMatrixScalar(matrix: Complex[][], scalar: Complex): Complex[][] {
  const fn = function (this: Complex) { return this.mul(c, scalar)};

  return forEachMatrixElement(matrix, fn);
}

CodePudding user response:

MDN Function.call() can take additional parameters as arguments. So the first parameter will always be the this bind, the second and onwards are arguments.

Wonder if this is what will solve your issue? So your code will look like

function forEachMatrixElement(matrix: Complex[][], func: Function, scalar?: Complex)

and

func.call(matrix[row][col], scalar)
  • Related