3

I am learning ECMAScript 2016. I tried to use template literals to build a simple function to figure tax, but I found when I use different loop styles, the function just returned me completely different results.

When I use for loop style:

const total = 30
function figureTax(literals) {
  let res = ''
  for ( let i = 0; i < literals.length; ++i) {
    res += literals[i]
    if (i < arguments.length) {
      res += arguments[i]
    }
  }
  // let i = 0
  // while (i < literals.length) {
  //   res += literals[i++]
  //   if (i < arguments.length) {
  //     res += arguments[i]
  //   }
  // }
  return res
}
const res = figureTax`Your tax is (${ total * 0.15 } with tax!)`
console.log(res)

It returned me

Your tax is (Your tax is (, with tax!) with tax!)4.5

When use while style:

const total = 30
function figureTax(literals) {
  let res = ''
  // for ( let i = 0; i < literals.length; ++i) {
  //   res += literals[i]
  //   if (i < arguments.length) {
  //     res += arguments[i]
  //   }
  // }
  let i = 0
  while (i < literals.length) {
    res += literals[i++]
    if (i < arguments.length) {
      res += arguments[i]
    }
  }
  return res
}
const res = figureTax`Your tax is (${ total * 0.15 } with tax!)`
console.log(res)

It returned me the correct result:

Your tax is (4.5 with tax!)

Anyone can explain it?

Liam_1998
  • 1,157
  • 3
  • 12
  • 27

4 Answers4

3

It has nothing to do with for or while loop. If you use tag functions the first argument is an array of the string literals and all the next are the interpolation variables. You use arguments which is all of the function's arguments. See below snippet:

const total = 30;

function figureTaxWithFor(literals, ...args) {
  
  let res = '';
  
  for ( let i = 0; i < literals.length; ++i) {
  
    res += literals[i];
  
    if (i < args.length) res += args[i];
  }

  return res;
}

function figureTaxWithWhile(literals, ...args) {
  
  let res = '';
  let i = 0;

  while (i < literals.length) {
    
    res += literals[i++];
  
    if (i - 1 < args.length) res += args[i - 1];
  }

  return res;
}

const res = figureTaxWithFor`Your tax is (${ total * 0.15 } with tax!)`;
const res2 = figureTaxWithWhile`Your tax is (${ total * 0.15 } with tax!)`;
console.log(res);
console.log(res2);
Alex G
  • 1,897
  • 2
  • 10
  • 15
2

To answer your question by changing your code as little as possible, it's because your while loop increments i before accessing arguments, but your for loop was not doing so. If you rewrite the for loop as follows, it also works:

const total = 30
function figureTax(literals) {
  let res = ''
  for ( let i = 0; i < literals.length;) {
    res += literals[i++]
    if (i < arguments.length) {
      res += arguments[i]
    }
  }
  return res
}
const res = figureTax`Your tax is (${ total * 0.15 } with tax!)`
console.log(res)
Scott Rudiger
  • 1,224
  • 12
  • 16
1

the difference comes from where you're incrementing i in your while loop:

res += literals[i++]

for your first iteration, this would return literals[0], but it would compare 1 < arguments.length and add arguments[1].

however, in your for loop, you're incrementing via ++i:

for ( let i = 0; i < literals.length; ++i) {

for your first iteration, this would return literals[**1**] and it would compare 1 < arguments.length and add arguments[1].

to fix the for loop, change to i++ and add + 1 where necessary:

const total = 30

function figureTax(literals) {
  let res = ''

  for ( let i = 0; i < literals.length; i++) {
    res += literals[i]

    if ((i + 1) < arguments.length) {
      res += arguments[i + 1]
    }
  }

  return res
}

const res = figureTax`Your tax is (${ total * 0.15 } with tax!)`
console.log(res)
//Your tax is (4.5 with tax!)

for more information, see What is the difference between ++i and i++?

Andrew Ault
  • 569
  • 3
  • 12
0

Your problem is to take the same index for literals as for arguments and while arguments[0] is equal to literals, you get the same content too.

To overcome this, you could take a rest syntax

figureTax(literals, ...params)

and catch all paramters and loop with the same index. This has the roblem of the last parameter as your approach.


Why not simplify the loop to a check of literals and arguments which have the same length.

function figureTax(literals) {
    let res = literals[0];
    for (let i = 1; i < literals.length; ++i) {
        res += arguments[i] + literals[i];
    }
    return res;
}

const total = 30
const res = figureTax`Your tax is (${ total * 0.15 } with tax!)`

console.log(res)
console.log(figureTax``);
Nina Scholz
  • 376,160
  • 25
  • 347
  • 392