Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<p>That's how the comparison operators work on objects:</p> <pre><code>var a = {}, b = {}; a === b; //false a == b; //false a &gt; b; //false a &lt; b; //false var c = { valueOf : function () { return 0; } }; var d = { valueOf : function () { return 1; } }; c === d; //false c == d; //false c &gt; d; //false c &lt; d; //true </code></pre> <h2>Under the hood</h2> <p>(sort of)</p> <h3>Part 1 : Equality</h3> <p>This is the easiest part. Both abstract equality (<code>==</code>, <a href="http://es5.github.com/#x11.9.3" rel="nofollow noreferrer">spec</a>) and strict equality (<code>===</code>, <a href="http://es5.github.com/#x11.9.6" rel="nofollow noreferrer">spec</a>) check if you're referring to the same object (sort of comparing references). In this case, they are obviously not, so they answer is <code>false</code> (<code>==</code> spec step 10, <code>===</code> spec step 7).</p> <p>Therefore, in both cases:</p> <pre><code>b1 == b2 //false b1 === b2 //false </code></pre> <h3>Part 2: The Comparison strikes back</h3> <p>Here comes the interesting part. Let's look at how the relational operators (<code>&lt;</code> and <code>&gt;</code>) <a href="http://es5.github.com/#x11.8.5" rel="nofollow noreferrer">are defined</a>. Let's follow the call chain in the two cases.</p> <pre><code>x = b1 //&lt;Buffer aa&gt; y = b2 //&lt;Buffer ab&gt; //11.8.5 The Abstract Relational Comparison Algorithm (http://es5.github.com/#x11.8.5) Let px be the result of calling ToPrimitive(x, hint Number). Let py be the result of calling ToPrimitive(y, hint Number). //9.1 ToPrimitive (http://es5.github.com/#x9.1) InputType is Object, therefore we call the internal [[DefaultValue]] method with hint Number. //8.12.8 [[DefaultValue]] (hint) http://es5.github.com/#x8.12.8 We try and fetch the object's toString method. If it's defined, call it. </code></pre> <p>And here we've reached the climax: What's a buffer's <code>toString</code> method? The answer lies deep inside node.js internals. If you want, <a href="https://github.com/joyent/node/blob/51f128d64b250dfeb128aab5117b5bbcd2cc51b5/lib/buffer.js#L389" rel="nofollow noreferrer">have at it</a>. What we can find out trivially is by experimentation:</p> <pre><code>&gt; b1.toString() '�' &gt; b2.toString() '�' </code></pre> <p>okay, that wasn't helpful. You'll notice that in the Abstract Relational Comparison Algorithm (what a big fancy name for <code>&lt;</code>), there's a step for dealing with strings. It just converts them to their numeric value - the char codes. Let's do that:</p> <pre><code>&gt; b1.toString().charCodeAt(0) 65533 &gt; b2.toString().charCodeAt(0) 65533 </code></pre> <p>65533 is an important number. It's the sum of two squares: <code>142^2 + 213^2</code>. It also happens to be the Unicode Replacement Character, a character signifying "I have no idea what happened". That's why its hexadecimal equivalent is FFFD.</p> <p>Obviously, <code>65533 === 65533</code>, so:</p> <pre><code>b1 &lt; b2 //is b1.toString().charCodeAt(0) &lt; b2.toString().charCodeAt(0) //is 65533 &lt; 65533 //false b1 &gt; b2 //following same logic as above, false </code></pre> <p>And that's that.</p> <h3>Dude, what the hell?</h3> <p>Okay, this must've been confusing since my efforts of explanation haven't been well thought through. To recap, here's what happened:</p> <ol> <li><p>You created a buffer. <a href="https://stackoverflow.com/users/1348195/benjamin-gruenbaum">Benjamin Gruenbaum</a> helped me recreate your test case by doing:</p> <p><code>var b1 = new Buffer([170]), b2 = new Buffer([171]);</code></p></li> <li><p>When outputting to console, the values are turned into their hex equivalent (see <a href="https://github.com/joyent/node/blob/51f128d64b250dfeb128aab5117b5bbcd2cc51b5/lib/buffer.js#L283" rel="nofollow noreferrer">Buffer#inspect</a>):</p> <p><code>170..toString(16) === 'aa'</code></p> <p><code>171..toString(16) === 'ab'</code></p></li> <li><p>However, internally, they represented invalid characters (since it's not hex encoding; again, you're free to delve into the implementation nitty gritty, I won't (oh the irony)). Therefore, when converted to a string, they were represented with the Unicode replacement character.</p></li> <li><p>Since they're different objects, any equality operator will return <code>false</code>.</p></li> <li><p>However, due to the way less-than and greater-than work, they were turned into strings (and then to numbers) for comparison. In light of point #3, that's the same value; therefore, they cannot be less-than or greater-than each other, leading to <code>false</code>.</p></li> </ol> <p>Finally, just to put a smile on your face:</p> <pre><code>b1 &lt;= b2 //true b1 &gt;= b2 //true </code></pre>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload