0

Firstly sorry for such vague question, I couldn't think of title which make sense.

I was trying to understand this line in JS (outputs: 12216520)

 color = +("0x" + color.slice(1).replace( 
    color.length < 5 && /./g, '$&$&'));

Can someone help me in understanding that how javascript is going to evaluate it?

I tried two snippet

   color = +`0x${color}`.slice(1).replace( 
    color.length < 5 && /./g, '$&$&');

This gives null in console

and

    color = "0x" + color.slice(1).replace( 
    color.length < 5 && /./g, '$&$&') + color;

This gives me 0xBA68C8 #BA68C8 in console

Whereas the first snippet outputs this 12216520

Code snippet for reference

console.log(lightOrDark('#BA68C8 '))
function lightOrDark(color) {
    var r, g, b, hsp;
    let co
    if (color.match(/^rgb/)) {
        color = color.match(/^rgba?\((\d+),\s*(\d+),\s*(\d+)(?:,\s*(\d+(?:\.\d+)?))?\)$/);
        r = parseInt(color[1]);
        g = parseInt(color[2]);
        b = parseInt(color[3]);

    } 
    else {
        color = +("0x" + color.slice(1).replace( 
        color.length < 5 && /./g, '$&$&'));
        r = color >> 16;
        g = color >> 8 & 255;
        b = color & 255;
    }
    hsp = Math.sqrt(
    0.299 * (r * r) +
    0.587 * (g * g) +
    0.114 * (b * b)
    );

    if (hsp>150) {
        return 'light';
    } 
    else {
        return 'dark';
    }
}

2 Answers 2

2

So, first of all, the and/or operators in Javascript can return things other than true or false. Javascript values can be "truthy" or "falsy", and if you chain a series of arguments with the && operator (a && b && c && d), the result of that operation will be the first argument in that chain that was falsy, or the last argument in the chain if none was. (It's easy to check from there that if you only pass true or false arguments, you get the expected result.) So, for a string whose length is 5 or greater, color.length < 5 && /./g is false, and for a string whose length is smaller, the result is /./g.

Next, Javascript has a concept of "implicit conversions": when you use an operation with an argument that has the wrong type for that operation, it will try to convert the argument to that type if it's at all possible. In particular, the expression +a is not a string addition operation (that would be a + b) but the positive equivalent of -b that changes a number's sign. +a doesn't do any changing of the sign, but it expects a number as an argument, and so it tries to convert a to a number. And in particular, if a is a string that starts with 0x, it will parse it as a hexadecimal number.

So let's go now step by step:

color  // "#BA68C8"
color.length  // 7
color.length < 5 && /./g  // false
color.slice(1)  // "BA68C8"
color.slice(1).replace(false, '$&$&')  // "BA68C8"
"0x" + color.slice(1).replace(false, '$&$&')  // "0xBA68C8"
+"0xBA68C8"  // 12216520 (the decimal equivalent to hexadecimal BA68C8)

Now, if the length of color is less than 5 (with "#FFF", for example), the first argument to .replace is the RegExp /./g. This matches every single character in a string. And the replacement value contains $&, which is a special code which gets substituted by the matched string. So:

color  // "#ABC"
color.length  // 4
color.length < 5 && /./g  // /./g
color.slice(1)  // "ABC"
color.slice(1).replace(/./g, '$&$&')  // "AABBCC"
"0x" + color.slice(1).replace(/./g, '$&$&')  // "0xAABBCC"
+"0xAABBCC"  // 11189196 (the decimal equivalent to hexadecimal AABBCC)
Sign up to request clarification or add additional context in comments.

2 Comments

Worth noting that color.length < 5 && /./g is both harder to read than it needs to be and error prone. If your color contains the string 'false', it will repeat that. (In practice this will probably never occur, but I'd still avoid writing it this way.)
@Ivar I considered mentioning that in the answer, but if color includes "false" as a substring, it will later be converted to NaN anyway, so it wouldn't make a difference here.
0

Firstly, for the original snippet:

color = +("0x" + color.slice(1).replace( 
color.length < 5 && /./g, '$&$&'));

Basically it's using to convert from Hexadecimal string to Decimal number. Here is how it's work:

var color = '#BA68C8';
color = color.slice(1).replace(color.length < 5 && /./g, '$&$&'); // This use to remove the '#' character from hex string.
console.log(color); // BA68C8
color = "0x" + color; // This use to add '0x' prefix to indicate the hex number
console.log(color); // 0xBA68C8
color = +color; // Convert to Decimal, this is relative to parseInt(color)
console.log(color); // 12216520

In your 2 snippet. The second one is nothing similar to the original snippet. While the first one gives null because you put the wrong variable in the braces. This is the right one:

color = +`0x${color.slice(1).replace( 
color.length < 5 && /./g, '$&$&')}`;

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.