Is it possible to overload Javascript mathematical operators for objects?

Asked

Viewed 71 times

1

I wanted to know how we can overload the subtraction operator, so that when the object is subtracted by another equal object, it returns a new object, with everything subtracted

Example:

var player = new Vector2(10, 10);
var mass = new Vector2(50, 50);

console.log(player - mass);

/*
Saída: Vector2 { X: -40, Y: -40 }
*/
  • Unfortunately, it is not possible

2 answers

4

The way you demonstrated (player - mass) will return to you NaN as an answer, because the - force conversion to number, which is not possible with objects.

If both objects are "equal" in structure, the simplest case is to create a function that receives the 2 objects that will have their equivalent properties subtracted to arrive at the expected result Saída: Vector2 { X: -40, Y: -40 }.

By creating a function that receives these 2 "equal" objects, you can simply return an object with the equivalent values of x and y subtracted:

class Vector2 {
 constructor(x, y) {
  this.x = x;
  this.y = y
 }
}

var player = new Vector2(10, 10);
var mass = new Vector2(50, 50);

function subtrairVector2 (player, mass) {
  // este if verifica se os objetos são instância de 'Vector2',
  // caso contrário, esta operacao irá ocasionar erros
  if (!(mass instanceof Vector2) || !(player instanceof Vector2)) {
    throw new Error('Not instance of Vector2 class')
  }
  
  return {
    x: player['x'] - mass['x'],
    y: player['y'] - mass['y'],
  }
}

console.log(subtrairVector2(player, mass));

You can also return a new Vector2, changing the function subtrairVector2 to return a new instance of that class:

class Vector2 {
 constructor(x, y) {
  this.x = x;
  this.y = y
 }
}

var player = new Vector2(10, 10);
var mass = new Vector2(50, 50);

function subtrairVector2 (player, mass) {
  // este if verifica se os objetos são instância de 'Vector2',
  // caso contrário, esta operacao irá ocasionar erros
  if (!(mass instanceof Vector2) || !(player instanceof Vector2)) {
    throw new Error('Not instance of Vector2 class')
  }
  
  // novos valores para 'x' e 'y'
  const x = player['x'] - mass['x']
  const y = player['y'] - mass['y']
  
  // cria e retorna uma nova instância de Vector2
  return new Vector2(x, y)
}

console.log(subtrairVector2(player, mass));

  • Just one suggestion: use TypeError instead of Error to notify that the error is due to wrong type parameters.

  • It’s not like that, it would be like Lua, in Lua you can define something called metatable, and in this metatable table(object) you can define functions like: _sub, __div, __Mul, _add. and in these functions you get the parameter a and b, which are a, the table in question, and b, the other argument, and you can return the sum there, using Return a.X - b.X;

  • So with this it is possible to do something like this: l
local Position = Vector2.new(10, 10)
local Target = Vector2.new(50, 50)

print(Position - Target)


3


Operator overload exists in Javascript?

What the question asks does not exist in Javascript. It is called Perator overloading, or, in Portuguese, overload of operators.

The behavior of Javascript operators is fixed to a set of types, with no possibility of extension.

To date, binary arithmetic operators such as +, -, *, / at all times will evaluate to a numerical value. It is even possible to customize as an arbitrary value used as operating is converted to the primitive number, but nothing can be done to cause the operator to result in a value other than number.

A crazy example that modifies the conversion process to type number using Symbol.toPrimitive:

class Vector2 {
  constructor(x, y) {
    Object.assign(this, { x, y });
  }
  
  // Modificamos a forma como objetos `Vector2` tornam-se primitivos
  [Symbol.toPrimitive](hint) {
    switch (hint) {
      case 'number':
        return Math.hypot(this.x, this.y);
      default:
        return `Vector2(${this.x}, ${this.y})`
    }
  }
}

const v1 = new Vector2(3, 4);
const v2 = new Vector2(6, 8);

// Convertendo para string:
console.log(`${v1}; ${v2}`);

// Conversão para primitivo `number` é feita implicitamente pelo `-`.
// v2 é convertido para 10; v1 é convertido para 5.
console.log(v2 - v1);

In short: there is no way to overload. There is even proposal so that this will one day be part of the language, but it is still far from becoming reality.

Alternatives

Since it is not possible to modify the behavior of language operators, one possible solution is to create functions that encapsulate the operator-analogous logic for an arbitrary type.

In the case of two-dimensional vectors, you could implement functions such as vec2_add, vec2_mult, etc.. This has already been demonstrated in the other reply.

Another alternative is to define the methods corresponding to the operators in the class itself. Instead of +, one can have a method add in the class itself. Thus:

class Vector2 {
  constructor(x, y) {
    Object.assign(this, { x, y });
  }
  
  add(other) {
    return new Vector2(this.x + other.x, this.y + other.y);
  }
}

const v1 = new Vector2(1, 2);
const v2 = new Vector2(5, 6);
const v3 = v1.add(v2);
console.log(v3); // { x: 6, y: 8 }

The advantage of this approach is that multiple calls can be chained.

Of course it’s not as pretty as wearing the +, but it’s what I see as most expressive in current Javascript.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.