What is the relation of the "+" operator to the "valueOf()" method in Javascript?

Asked

Viewed 60 times

5

I have a question about the operator +.

In this answer on the operator, the following was said:

The + can also play the role of a binary operator. In that case, operates on two values. In this sense, the + may have two different functions, depending on the type of the two operands:

  • Carry out the summing up two values (addition); or:
  • Carry out the concatenation two-string.

...

  • First, the operator converts the two operands to primitive values. After that, it will follow one of the two modes:
    1. String mode: If either of the two operands is a string, the other operand will be converted to the type string corresponding. The two values will be concatenated and returned as string.
    2. Numerical mode: Otherwise (none of the operands is string), it will convert both operators to type number. Both values will be added later and returned as number.

I noticed some behaviors. The operator + "it seems" that invokes the function valueOf whenever it is present within an object. See below:

function User() {
  return {
    valueOf: () => 'Brendam'
  }
}

const result = new User() + new User()

console.log(result)

As seen above, the + did something more than I expected. But it didn’t end there. The same behavior happens if we try to use this operation to convert a literal object that has the same method, but returns a number. If it returns a string, we receive NaN as a result:

let obj = {
  valueOf: function() {
    return 'Brendam'
  }
}

let obj2 = {
  valueOf: function() {
    return 10;
  }
};

console.log(+obj)  // NaN
console.log(+obj2) // 10

I confess that I was very confused by the use of this operator:

  • Why + invokes the valueOf? What is the relationship between them?
  • Only this operator does this? Or does the same behavior repeat for some other operator?
  • 2

    bizarre things from javascript, I can’t imagine new User() + new User() in java, c, c++ or c# for example :D

  • 2

    @Ricardopunctual would be so simple if I made just one exception...

  • 1

    because it is, javascript deceives us, not error in many situations, but returns something difficult to understand

1 answer

5


This is a behavior that is due to the nature of coercion typical of Javascript. It is a language that historically relies on automatic type conversion, so there are several mechanisms for this to be done.

In the case of + (both binary and unary) and most other operators performing the conversion to the expected type, there are a number of steps to be taken so that the Runtime decided as convert to the appropriate value.

Below we explore how the conversion of objects to an expected primitive works. In the case of this answer, the expected result is number, but may vary depending on the operator used.

In the end, the steps are very similar. Just follow the algorithm described in spec.

Why + invokes the valueOf? What is the relationship between them?

Why is language design.

  • In the case of the anointing +, the specification (among the many listed steps) applies the abstract operation ToNumber that, in the case of objects (i.e., values in which the valueOf is taken into account), flame ToPrimitive, what call OrdinaryToPrimitive, which finally calls the method valueOf on objects.

  • In the case of torque +, that operates in "string mode" or "numeric mode", this may occur:

    1. In string mode, the abstract operation is called ToString to operands. Following for objects, invoke ToPrimitive which, as we have seen above, will invoke OrdinaryToPrimitive.
    2. In numerical mode, it is called the abstract operation ToNumeric, so that similar steps occur to what occurred at the anointing, only for the two arguments.

Note, in the algorithm of OrdinaryToPrimitive, that he first tries to summon valueOf and, if not available, has fallback at the toString. This already explains the behavior demonstrated in the question.

It is something very subtle and little used (many people don’t even know that the valueOf exists), so you don’t see much about it.

I wouldn’t expect anyone (except perhaps library creators) to use this mechanism to develop code on a daily basis. It’s something extremely obscure.

And of course, Javascript had to complicate it a bit more. In most type conversions, if there is a method defined by @@toPrimitive (that’s a well known Symbol) in the object to which the conversion is to be performed, it will be used. Basically, before the abstract operation is invoked OrdinaryToPrimitive, the implementation tries to call the method defined by this well known Symbol. In case he’s undefined, is used OrdinaryToPrimitive as fallback.

To understand, think about @@toPrimitive as a conversion operation nonordinary. In case it does not exist, conversion is used ordinary.


Only the operator + does it? Or the same is repeated for some other?

This behavior nay is unique to the +.

As Javascript is a language that makes several types of coercion typical. Therefore, most operators who make type coercion automatically are "susceptible" to the method valueOf. This is because the various conversions that Javascript makes culminate in the abstract operation OrdinaryToPrimitive which, as we have seen above, ends up invoking the valueOf.

By default, it’s called the valueOf. If this does not exist, it is invoked toString. In the case of coercion aiming at a conversion to the string type, the toString is called before the valueOf, if it exists. The @@toPrimitive is always prioritized, if there is.


On the last topic of the question, the result is different because, in the first case, the + was used as a binary operator that performs concatenation. In the second example, the + was used as an unary operator in order to carry out the conversion to type number.

Browser other questions tagged

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