26

In JavaScript, is there any circumstance where there is a semantic difference between these two options?

foo.bar + ''

...and...

'' + foo.bar

I would've expected the latter to more reliably coerce the result to a string, but I can't find any discussion of this (after much Googling) nor any example where it seems to matter.

3
  • Related: stackoverflow.com/questions/31845895/…
    – Callat
    Commented Jul 27, 2018 at 19:38
  • Isn't the most readable way to do string coercion String(foo.bar)?
    – Neil
    Commented Jul 27, 2018 at 20:38
  • 1
    @Neil Yes, it is, there is however a semantic difference in that the global String variable could be overwritten.
    – Bergi
    Commented Jul 28, 2018 at 13:26

5 Answers 5

16

Both are the same.

There is only a difference if there are other + (on the left or the right). In other words:

1 + 1 + ''                          // results in '2'

Is not the same as:

'' + 1 + 1                          // results in '11'
4
  • 2
    To be fair, this does not match the OP's foo.bar + '' versus '' + foo.bar comparison.
    – trincot
    Commented Jul 27, 2018 at 19:54
  • 6
    @trincot That is already answered by "Both are the same". I just wanted to include this related example that could produce a difference. After all, we don't know how OP is using this exactly. Commented Jul 27, 2018 at 19:56
  • @trincot ... It might as well be something + foo.bar + '' or '' + foo.bar + something Commented Jul 27, 2018 at 19:58
  • Yes, I agree. Precedence rules (left to right) will make the left side not foo.bar at the moment of the addition the OP is looking at. But I can see that it would be interesting if the OP is not actually looking for that precise case only.
    – trincot
    Commented Jul 27, 2018 at 20:01
13

They are the same as others have already mentioned, with additional considerations listed by @Zohaib Ijaz:

var values = [
  undefined,
  null,
  false,
  true,
  0,
  -1,
  1,
  NaN,
  Infinity,
  '',
  '123',
  'abc123',
  '123abc',
  [],
  [0],
  [1],
  {},
  {a: 1},
  function(){}   
];
var foo = {bar: null};

values.forEach(function(value) {
  foo.bar = value;
  
  console.log("foo.bar + '':", foo.bar + '');
  console.log("'' + foo.bar:", '' + foo.bar);
});

However there are significant differences, when you have more than 2 operands as mentioned by @ibrahim mahrir:

var values = [
  undefined,
  null,
  false,
  true,
  0,
  -1,
  1,
  NaN,
  Infinity,
  '',
  '123',
  'abc123',
  '123abc',
  [],
  [0],
  [1],
  {},
  {a: 1},
  function(){}   
];
var foo = {bar: null};

values.forEach(function(value) {
  foo.bar = value;
  
  console.log("foo.bar + '' + foo.bar:", foo.bar + '' + foo.bar);
  console.log("'' + foo.bar + '':", '' + foo.bar + '');
});

1
  • 9
    Well of course there's a difference between foo.bar + '' + foo.bar and '' + foo.bar + ''. Expecting those to be the same would be like expecting 1 + 2 + 1 and 2 + 1 + 2 to be the same. ibrahim's example is a bit subtler. Commented Jul 28, 2018 at 5:13
5

If one of the operands is a string, valueOf() or toString() will be called on the other one, so yes they are exactly the same.

12.8.3 of the spec:

 AdditiveExpression + MultiplicativeExpression
  1. Let lref be the result of evaluating AdditiveExpression.

  2. Let lval be ? GetValue(lref).

  3. Let rref be the result of evaluating MultiplicativeExpression.

  4. Let rval be ? GetValue(rref).

  5. Let lprim be ? ToPrimitive(lval).

  6. Let rprim be ? ToPrimitive(rval).

  7. If Type(lprim) is String or Type(rprim) is String, then

    a. Let lstr be ? ToString(lprim).

    b. Let rstr be ? ToString(rprim).

    c. Return the String that is the result of concatenating lstr and rstr

2
  • This is not entirely true: before toString is called on the non-string argument, the ToPrimitive step is executed which may involve a call to valueOf, and if that result is a primitive, toString is never called (not to be confused with ToString in the reference which is about converting one primitive type to another, which does not involve a call to toString).
    – trincot
    Commented Jul 28, 2018 at 7:16
  • @trincot yup, clarified that Commented Jul 28, 2018 at 8:15
3

Here are few rules taken from here

  • If at least one operand is an object, it is converted to a primitive value (string, number or boolean);
  • After conversion, if at least one operand is string type, the second operand is converted to string and the concatenation is executed;
  • In other case both operands are converted to numbers and arithmetic addition is executed.
3

No, there is no difference.

If foo.bar is not a primitive value then first valueOf is called on it. If that still does not return a primitive value, toString is called on it. If that still does not return a primitive value, an error is triggered.

In all this, the foo.bar object is not aware in which context valueOf or toString are called. There is no way the object can differentiate between the two cases you mention. It does not even have to be one of those two.

Finally, there is no way to set a trap on the + operator, so you could know its operands.

Here is a demo of how valueOf and toString are called in that order:

const foo = { 
    bar: {
        valueOf() {
            console.log('valueOf');
            return this; // not a primitive value, so now toString will be called.
        },
        toString() {
            console.log('toString');
            return "1";
        }
    }
}

console.log(foo.bar + '');
console.log("====");
console.log('' + foo.bar);

Not the answer you're looking for? Browse other questions tagged or ask your own question.