0

Whenever there are tab switches or similar structures, I see this pattern:

const tabs = {
  FIRST: 'FIRST',
  SECOND: 'SECOND',
}

const getActiveClassName = current => activeTab === current ? 'active' : ''

...

const activeTab = tabs.FIRST

<button className={getActiveClassName(tabs.FIRST)}/>
<button className={getActiveClassName(tabs.SECOND)}/>

I thought that going letter by letter in String Comparison must be inefficient, so I wrote a test and compared it to Object Equality in hope that comparing references would be much faster:

const tabs = {
  FIRST: {},
  SECOND: {},
}

The result is that there is almost no difference. Why?

enter image description here

The JSPerf test is here.

Qwerty
  • 29,062
  • 22
  • 108
  • 136
  • "string comparison must be utterly inefficient"? Why do you think so? – Ram Oct 28 '18 at 19:21
  • 1
    Related: [Premature Optimization](http://wiki.c2.com/?PrematureOptimization) – Ram Oct 28 '18 at 19:24
  • I was feeling poetic, I changed the wording to better express the problem. I already know the topic so thank you for the link, I will read it. Anyway, be sure that this question is just for science, I am not doing anything. – Qwerty Oct 28 '18 at 19:29
  • 1
    Primitives are references to items in memory. If duplicate primitives containing the same value reference the same memory location (I don't know if that's the case), then the behavior you see would make sense. – CertainPerformance Oct 28 '18 at 19:35
  • @CertainPerformance So the engine knows to compare references instead of going inside the string? Yeah, that would totally make sense. Cool – Qwerty Oct 28 '18 at 19:37
  • 2
    @undefined while your comments is a valid one, ... Nevertheless, whenever one sees something unexpected, it's really better to find an explanation. Because the gained experience may come in handy somewhere else some day. (Who knows ... to find a cure for cancer or to solve global warming. ) – bvdb Oct 28 '18 at 19:37

2 Answers2

3

String comparison does not always need to go letter by letter.

Strings are not implemented as raw data values (like the other primitive types), but are actually references to their (immutable) contents. This, and the fact that they are immutable, allows some optimisations that might occur in your example:

  • Two strings referencing the same content memory are know to be equal. If you assign activeTab = tabs.FIRST and then compare activeTab === tabs.FIRST I'd bet that only the reference will be compared.
  • Two strings that are unequal are only compared until the first letter that distinguishes them. Comparing "First" === "Second" will need to access only one letter.
  • Since string literals are typically interned, when the engines knows that it does compare two interned strings (not dynamically built ones) it will only need to compare their references. Two different references to interned string contents mean two different contents, as interned strings with the same contents would be share their memory. So even your activeLongString can be distinguished from the other constants in longStrings by a constant comparison.
Bergi
  • 630,263
  • 148
  • 957
  • 1,375
0

Deep down in the belly of the computer, string comparisons rely on the C library and its strcmp(3) function.

As this is one of the most used functions, C library developers have optimized the heck out of it. In particular, when two strings are found to differ by at least one byte, the strings may be considered different and the comparison short-circuits.

For s*hit and giggles, you may actually find how strcmp has been implemented in (some very old version of) macOS in x86_64 assembly:

https://opensource.apple.com/source/Libc/Libc-825.26/x86_64/string/strcmp.s.auto.html

Note however two things:

  1. These type of things are close to the metal and JS is not
  2. Things like string comparison implementation depends on the OS

You are therefore bound to get weird results since the effects are so tiny and depend on the OS version to the next. Mind you that a JS runtime has to go through many hoops to get to the string comparison and the associated noise completely overshadows the cost of the comparison operator itself.

My advice for all JS developers would be to focus solely on code correctness and UX.

Elias Toivanen
  • 838
  • 7
  • 12
  • While there are better answers that truly clarify how the JS engine works under the hood and that it can short-circuit without actually comparing the strings, it was indeed interesting to read the linked source for the fact, that string comparison might **run in parallel**. – Qwerty Oct 28 '18 at 20:04