Are commas meant to be syntactically valid in Javascript if statements? [duplicate] - javascript

This question already has answers here:
What does the comma operator do in JavaScript?
(5 answers)
Closed 9 years ago.
The last few days, I've been helping a friend learn Javascript. It's his first language in years and he remembers virtually nothing, so he's been starting pretty much entirely from scratch. He's been going through a simple tutorial and I've been providing him with some exercises to help him practice. The most recent exercise I gave him was the (apparently) classic FizzBuzz problem. He solved it with a bit of help, but he did something very interesting while working out his solution. He came up with the following code:
for (var x = 1; x <= 100; x++) {
if (x%3 == 0, x%5 != 0) {
console.log("Fizz");
}
else if (x%3 != 0, x%5 == 0) {
console.log("Buzz");
}
else if (x%3 == 0, x%5 == 0) {
console.log("FizzBuzz");
}
else {
console.log(x);
}
}
He wasn't familiar with boolean comparison operators, so he didn't use && and instead used commas. My expectation was that it would crash and say something about a syntax error, but to my surprise it ended up running fine and just printing out a bunch of "Fizz" and "Buzz" lines, with no "FizzBuzz" or numbers. Needless to say, I was confused, so I did a bit of experimentation. My first test was to run this:
if (true, true) console.log('true, true');
if (true, false) console.log('true, false');
if (false, true) console.log('false, true');
if (false, false) console.log('false, false');
Which gave me two lines of output:
'true, true'
'false, true'
From that, I made the guess that all comma did was cause it to evaluate nothing but the last expression in the list. I then tried running this code:
for (var i = 0; i < 16; i++) {
if ((Math.floor(i / 8) == 1), (Math.floor(i / 4) == 1), (Math.floor(i / 2) == 1), (i % 2 == 1)) {
console.log(i);
}
}
The output I got was all the odd numbers from 1-15, which confirmed my guess from my first test (since the last boolean in the comma-separated list was flipping every other iteration).
After all that long-winded context, my question is this: Is this comma syntax a known and intentional piece of the Javascript engine, or is it a strange, overlooked quirk of the interpreter? I know commas can be used for a few other things (initializing multiple variables in one line, declaring arrays, and separating parameters jump to mind), but I've never heard of them being used in conditional statements like this in any language, and I'm curious if anyone else knows whether or not this code should even run.
For reference, the FizzBuzz code and the second test I ran were both done using node, and the first test I ran was done in the Javascript console in Chrome, so it doesn't seem to be just a browser- or node-exclusive quirk if indeed it is one. Also, if you actually read this far, thank you.

The comma is an actual operator. It evaluates both of its operands (from left to right) and returns the value of the second operand.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Comma_Operator
Its most common usage is to supply multiple parameters in a for loop, but it can also be used for other purposes.

Related

What does the declared function returnMe() do in this loop?

I'm a very beginner learning Javascript, alongside other code languages, and while looking at information here and in other sites, I've pieced together a simple code loop:
function returnMe() {
for (let i = 1; i <= 10; i++) {
if (i == 10) return i;
console.log(i)
}
}
console.log(returnMe());
I understand what everything does except the function I've created. The function is to stop the loop from continuing endlessly, but I'm not sure how exactly I've enabled that, nor why it should be logged (though I figured out that both pieces must be there for it to work or else it will either not work or come back as undefined.)
I was hoping someone here could help quickly define the simple issue for me, since search engines and other sites believe I'm asking what the return function is instead (which makes sense why), and I just need to understand how that bit works.
the output of the function is
1
2
3
4
5
6
7
8
9
10
it will console log every number from 1 to 9 in the for loop and then it will return 10 which will be printed outside
The For Loop Consists Of for (let i = 1; i <= 10; i++) the parameters: Initiatlisation, Condition, Incrementation. So When You Use i<=10 you are allowing the function to run until the value is less than 10.
Going further It will console log all the numbers from 1 to 10 because of the console.log(i) afterwards. Then at i=10 it will return the value which will be then displayed by console.log(returnMe());

Multiconditional / Mutlivariable Javascript Switch Statement? [duplicate]

This question already has answers here:
Can I use a case/switch statement with two variables?
(9 answers)
Closed 2 years ago.
I'm coding a Discord bot with the javascript API, and I have an idea that I'm not sure would work, but would be a massive optimization.
Right now i'm adding a Rock Paper Scissors minigame into my bot, and I need it comparing the users guess (A sent emoji in the chat) to its own guess (A random number between 0-2 to represent the emoji of choice), and for now i have a line of if else doing that.
e.g, instead of
if(botGuess == 0 && msg.content.includes("/*unicode fist*/"){
//tie
}
I put it in a Switch statement... kinda like this??
switch(botGuess, msg){
case botGuess = 0, msg.content.includes("/*unicode fist*/"):
//tie
break;
}
I've just been wondering for a while, is this possible, and if so am I doing it right? As of now I have alot of if else statements, and switching to an advanced switch statement like the one I thought of above would give me ease of mind.
EDIT: I've found a workaround thanks to Simperfy. I'm concatenating both variables into a string and treating them both as one variable.
e.g.
var guesses = botGuess + "|" + msg.content;
switch(guesses){
case guesses.contains("0" && "/*unicode_fist*/"):
//tie
break;
}
A switch statement can only support a single unit of data. What you could do however, is concatenate two units of data into one. In javascript you can do this by basic multiplication:
switch (i + 1000 * j)
{
case 1002: ... // i = 2, j = 1
case 3004: ... // i = 4, j = 3
}
Note that this requires that i < 1000 and no negative numbers etc. Generally speaking a pattern like this isn't recommended. It is also simply not a clean style in any way, and I find it hard to imagine a situation where you would ever need something like this. I suggest editing your question to specify your scenario.

Ternary Operator use to increase variable

Is it a good practice to use the ternary operator for this:
answersCounter = answer.length != 0 ? ++answersCounter : answersCounter;
This is a question that I always asked myself as it happens quite often. Or, is it better to use a normal if statement? For me, this looks much cleaner in one line.
This is just opinion, but I think that writing the increment like you have it is somewhat poor style.
Assigning a variable to a pre-incremented version of itself is a little bit confusing. To me, the best code is the clearest (excepting nods to optimization where necessary), and sometimes brevity leads to clarity and sometimes it does not (see anything written in Perl... I kid, sorta).
Have you ever had the programming trick question of:
int i = 5;
i += i++ + i;
Or something similar? And you think to yourself who would ever need to know how that works out since when would you ever assign a variable to the pre/post increment version of itself? I mean, you would never ever see that in real code, right?
Well, you just provided an example. And while it is parseable, it is not idiomatic and not clearer than a straight forward if.
E.g.
if (answer.length != 0) answersCounter++;
Of course, some people don't like if statements with out braces, and don't like braces without newlines, which is probably how you ended up with the ternary. Something with the coding style needs to be re-evaluated though if it is resulting in (subjectively) worse code to avoid a few carriage returns.
Again, this is opinion only, and certainly not a rule.
For Javascript
As it's unclear whether OP is asking about Java, JavaScript or genuinely both.
Also know this is an old question but I've been playing with this and ended up here so thought it worth sharing.
The following does nothing, as incrementers within ternary operators don't work as expected.
let i = 0;
const test = true;
i = test ? i++ : i--;
console.log(i) // 0
Switching ++ to +1 and -- to -1 does work.
However it conceptually is a little strange. We are creating an increment of the variable, then assigning that incremented variable back to the original. Rather than incrementing the variable directly.
let i = 0;
const test = true;
i = test ? i+1 : i-1;
console.log(i) // 1
You can also use the logical operators && and ||.
However I personally find this harder to read and know for sure what will be output without testing it.
let i = 0;
const test = true;
i = test && i+1 || i-1;
console.log(i) // 1
But at the end of the day as commented above, an if else statement seems to be the clearest representation.
This increments the variable directly, and if brevity is the aim then it can still all go on one line.
let i = 0;
const test = true;
if (test) { i++ } else { i-- }
console.log(i) // 1

How to shorten my conditional statements

I have a very long conditional statement like the following:
if(test.type == 'itema' || test.type == 'itemb' || test.type == 'itemc' || test.type == 'itemd'){
// do something.
}
I was wondering if I could refactor this expression/statement into a more concise form.
Any idea on how to achieve this?
Put your values into an array, and check if your item is in the array:
if ([1, 2, 3, 4].includes(test.type)) {
// Do something
}
If a browser you support doesn't have the Array#includes method, you can use this polyfill.
Short explanation of the ~ tilde shortcut:
Update: Since we now have the includes method, there's no point in using the ~ hack anymore. Just keeping this here for people that are interested in knowing how it works and/or have encountered it in other's code.
Instead of checking if the result of indexOf is >= 0, there is a nice little shortcut:
if ( ~[1, 2, 3, 4].indexOf(test.type) ) {
// Do something
}
Here is the fiddle: http://jsfiddle.net/HYJvK/
How does this work? If an item is found in the array, indexOf returns its index. If the item was not found, it'll return -1. Without getting into too much detail, the ~ is a bitwise NOT operator, which will return 0 only for -1.
I like using the ~ shortcut, since it's more succinct than doing a comparison on the return value. I wish JavaScript would have an in_array function that returns a Boolean directly (similar to PHP), but that's just wishful thinking (Update: it now does. It's called includes. See above). Note that jQuery's inArray, while sharing PHP's method signature, actually mimics the native indexOf functionality (which is useful in different cases, if the index is what you're truly after).
Important note: Using the tilde shortcut seems to be swathed in controversy, as some vehemently believe that the code is not clear enough and should be avoided at all costs (see the comments on this answer). If you share their sentiment, you should stick to the .indexOf(...) >= 0 solution.
A little longer explanation:
Integers in JavaScript are signed, which means that the left-most bit is reserved as the sign bit; a flag to indicate whether the number is positive or negative, with a 1 being negative.
Here are some sample positive numbers in 32-bit binary format:
1 : 00000000000000000000000000000001
2 : 00000000000000000000000000000010
3 : 00000000000000000000000000000011
15: 00000000000000000000000000001111
Now here are those same numbers, but negative:
-1 : 11111111111111111111111111111111
-2 : 11111111111111111111111111111110
-3 : 11111111111111111111111111111101
-15: 11111111111111111111111111110001
Why such weird combinations for the negative numbers? Simple. A negative number is simply the inverse of the positive number + 1; adding the negative number to the positive number should always yield 0.
To understand this, let's do some simple binary arithmetic.
Here is how we would add -1 to +1:
00000000000000000000000000000001 +1
+ 11111111111111111111111111111111 -1
-------------------------------------------
= 00000000000000000000000000000000 0
And here is how we would add -15 to +15:
00000000000000000000000000001111 +15
+ 11111111111111111111111111110001 -15
--------------------------------------------
= 00000000000000000000000000000000 0
How do we get those results? By doing regular addition, the way we were taught in school: you start at the right-most column, and you add up all the rows. If the sum is greater than the greatest single-digit number (which in decimal is 9, but in binary is 1) we carry the remainder over to the next column.
Now, as you'll notice, when adding a negative number to its positive number, the right-most column that is not all 0s will always have two 1s, which when added together will result in 2. The binary representation of two being 10, we carry the 1 to the next column, and put a 0 for the result in the first column. All other columns to the left have only one row with a 1, so the 1 carried over from the previous column will again add up to 2, which will then carry over... This process repeats itself till we get to the left-most column, where the 1 to be carried over has nowhere to go, so it overflows and gets lost, and we're left with 0s all across.
This system is called 2's Complement. You can read more about this here:
2's Complement Representation for Signed Integers.
Now that the crash course in 2's complement is over, you'll notice that -1 is the only number whose binary representation is 1's all across.
Using the ~ bitwise NOT operator, all the bits in a given number are inverted. The only way to get 0 back from inverting all the bits is if we started out with 1's all across.
So, all this was a long-winded way of saying that ~n will only return 0 if n is -1.
You can use switch statement with fall thru:
switch (test.type) {
case "itema":
case "itemb":
case "itemc":
case "itemd":
// do something
}
Using Science: you should do what idfah said and this for fastest speed while keep code short:
THIS IS FASTER THAN ~ Method
var x = test.type;
if (x == 'itema' ||
x == 'itemb' ||
x == 'itemc' ||
x == 'itemd') {
//do something
}
http://jsperf.com/if-statements-test-techsin
(Top set: Chrome, bottom set: Firefox)
Conclusion :
If possibilities are few and you know that certain ones are more likely to occur than you get maximum performance out if || ,switch fall through , and if(obj[keyval]).
If possibilities are many, and anyone of them could be the most occurring one, in other words, you can't know that which one is most likely to occur than you get most performance out of object lookup if(obj[keyval]) and regex if that fits.
http://jsperf.com/if-statements-test-techsin/12
i'll update if something new comes up.
If you are comparing to strings and there is a pattern, consider using regular expressions.
Otherwise, I suspect attempting to shorten it will just obfuscate your code. Consider simply wrapping the lines to make it pretty.
if (test.type == 'itema' ||
test.type == 'itemb' ||
test.type == 'itemc' ||
test.type == 'itemd') {
do something.
}
var possibilities = {
"itema": 1,
"itemb": 1,
"itemc": 1,
…};
if (test.type in possibilities) { … }
Using an object as an associative array is a pretty common thing, but since JavaScript doesn't have a native set you can use objects as cheap sets as well.
if( /^item[a-d]$/.test(test.type) ) { /* do something */ }
or if the items are not that uniform, then:
if( /^(itema|itemb|itemc|itemd)$/.test(test.type) ) { /* do something */ }
Excellent answers, but you could make the code far more readable by wrapping one of them in a function.
This is complex if statement, when you (or someone else) read the code in a years time, you will be scanning through to find the section to understand what is happening. A statement with this level of business logic will cause you to stumble for a few seconds at while you work out what you are testing. Where as code like this, will allow you to continue scanning.
if(CheckIfBusinessRuleIsTrue())
{
//Do Something
}
function CheckIfBusinessRuleIsTrue()
{
return (the best solution from previous posts here);
}
Name your function explicitly so it immediately obvious what you are testing and your code will be much easier to scan and understand.
You could put all the answers into a Javascript Set and then just call .contains() on the set.
You still have to declare all the contents, but the inline call will be shorter.
Something like:
var itemSet = new Set(["itema","itemb","itemc","itemd"]);
if( itemSet.contains( test.type ){}
One of my favorite ways of accomplishing this is with a library such as underscore.js...
var isItem = _.some(['itema','itemb','itemc','itemd'], function(item) {
return test.type === item;
});
if(isItem) {
// One of them was true
}
http://underscorejs.org/#some
another way or another awesome way i found is this...
if ('a' in oc(['a','b','c'])) { //dosomething }
function oc(a)
{
var o = {};
for(var i=0;i<a.length;i++) o[a[i]]='';
return o;
}
of course as you can see this takes things one step further and make them easy follow logic.
http://snook.ca/archives/javascript/testing_for_a_v
using operators such as ~ && || ((),()) ~~ is fine only if your code breaks later on. You won't know where to start. So readability is BIG.
if you must you could make it shorter.
('a' in oc(['a','b','c'])) && statement;
('a' in oc(['a','b','c'])) && (statements,statements);
('a' in oc(['a','b','c']))?statement:elseStatement;
('a' in oc(['a','b','c']))?(statements,statements):(elseStatements,elseStatements);
and if you want to do inverse
('a' in oc(['a','b','c'])) || statement;
Just use a switch statement instead of if statement:
switch (test.type) {
case "itema":case "itemb":case "itemc":case "itemd":
// do your process
case "other cases":...:
// do other processes
default:
// do processes when test.type does not meet your predictions.
}
Switch also works faster than comparing lots of conditionals within an if
For very long lists of strings, this idea would save a few characters (not saying I'd recommend it in real life, but it should work).
Choose a character that you know won't occur in your test.type, use it as a delimiter, stick them all into one long string and search that:
if ("/itema/itemb/itemc/itemd/".indexOf("/"+test.type+"/")>=0) {
// doSomething
}
If your strings happen to be further constrained, you could even omit the delimiters...
if ("itemaitembitemcitemd".indexOf(test.type)>=0) {
// doSomething
}
...but you'd have to be careful of false positives in that case (e.g. "embite" would match in that version)
For readability create a function for the test (yes, a one line function):
function isTypeDefined(test) {
return test.type == 'itema' ||
test.type == 'itemb' ||
test.type == 'itemc' ||
test.type == 'itemd';
}
then call it:
…
if (isTypeDefined(test)) {
…
}
...
I think there are 2 objectives when writing this kind of if condition.
brevity
readability
As such sometimes #1 might be the fastest, but I'll take #2 for easy maintenance later on. Depending on the scenario I will often opt for a variation of Walter's answer.
To start I have a globally available function as part of my existing library.
function isDefined(obj){
return (typeof(obj) != 'undefined');
}
and then when I actually want to run an if condition similar to yours I'd create an object with a list of the valid values:
var validOptions = {
"itema":1,
"itemb":1,
"itemc":1,
"itemd":1
};
if(isDefined(validOptions[test.type])){
//do something...
}
It isn't as quick as a switch/case statement and a bit more verbose than some of the other examples but I often get re-use of the object elsewhere in the code which can be quite handy.
Piggybacking on one of the jsperf samples made above I added this test and a variation to compare speeds. http://jsperf.com/if-statements-test-techsin/6 The most interesting thing I noted is that certain test combos in Firefox are much quicker than even Chrome.
This can be solved with a simple for loop:
test = {};
test.type = 'itema';
for(var i=['itema','itemb','itemc']; i[0]==test.type && [
(function() {
// do something
console.log('matched!');
})()
]; i.shift());
We use the first section of the for loop to initialize the arguments you wish to match, the second section to stop the for loop from running, and the third section to cause the loop to eventually exit.

The most performant way to check if a string is blank (i.e. only contains whitespace) in JavaScript?

I need to write a function which tests, if given string is "blank" in a sense that it only contains whitespace characters. Whitespace characters are the following:
'\u0009',
'\u000A',
'\u000B',
'\u000C',
'\u000D',
' ',
'\u0085',
'\u00A0',
'\u1680',
'\u180E',
'\u2000',
'\u2001',
'\u2002',
'\u2003',
'\u2004',
'\u2005',
'\u2006',
'\u2007',
'\u2008',
'\u2009',
'\u200A',
'\u2028',
'\u2029',
'\u202F',
'\u205F',
'\u3000'
The function will be called a lot of times, so it must be really, really performant. But shouldn't take too much memory (like mapping every character to true/false in an array). Things I've tried out so far:
regexp - not quite performant
trim and check if length is 0 - not quite performant, also uses additional memory to hold the trimmed string
checking every string character against a hash set containing whitespace characters (if (!whitespaceCharactersMap[str[index]]) ...) - works well enough
my current solution uses hardcoded comparisons:
function(str) {
var length = str.length;
if (!length) {
return true;
}
for (var index = 0; index < length; index++)
{
var c = str[index];
if (c === ' ')
{
// skip
}
else if (c > '\u000D' && c < '\u0085')
{
return false;
}
else if (c < '\u00A0')
{
if (c < '\u0009')
{
return false;
}
else if (c > '\u0085')
{
return false;
}
}
else if (c > '\u00A0')
{
if (c < '\u2028')
{
if (c < '\u180E')
{
if (c < '\u1680')
{
return false;
}
else if(c > '\u1680')
{
return false;
}
}
else if (c > '\u180E')
{
if (c < '\u2000')
{
return false;
}
else if (c > '\u200A')
{
return false;
}
}
}
else if (c > '\u2029')
{
if (c < '\u205F')
{
if (c < '\u202F')
{
return false;
}
else if (c > '\u202F')
{
return false;
}
}
else if (c > '\u205F')
{
if (c < '\u3000')
{
return false;
}
else if (c > '\u3000')
{
return false;
}
}
}
}
}
return true;
}
This seems to work 50-100% faster than hash set (tested on Chrome).
Does anybody see or know further options?
Update 1
I'll answer some of the comments here:
It's not just checking user input for emptyness. I have to parse certain data format where whitespace must be handled separately.
It is worth optimizing. I've profiled the code before. Checking for blank strings seems to be an issue. And, as we saw, the difference in performance between approaches can be up to 10 times, it's definitely worth the effort.
Generally, I find this "hash set vs. regex vs. switch vs. branching" challenge very educating.
I need the same functionality for browsers as well as node.js.
Now here's my take on performance tests:
http://jsperf.com/hash-with-comparisons/6
I'd be grateful if you guys run these tests a couple of times.
Preliminary conclusions:
branchlessTest (a^9*a^10*a^11...) is extremely fast in Chrome and Firefox, but not in Safari. Probably the best choice for Node.js from performance perspective.
switchTest is also quite fast on Chrom and Firefox, but, surprizingly the slowest in Safari and Opera
Regexps with re.test(str) perform well everywhere, even fastest in Opera.
Hash and branching show almost identically poor results almost everywhere. Comparision is also similar, often worst performance (this may be due to the implementation, check for ' ' should be the first one).
To sum up, for my case I'll opt to the following regexp version:
var re = /[^\s]/;
return !re.test(str);
Reasons:
branchless version is cool in Chrome and Firefox but isn't quite portable
switch is too slow in Safari
regexps seem to perform well everywhere, they'll also very compact in code
Hard-coded solution seems the best, but I think switch should be faster. It depends on the way JavaScript interpreter handles these (most compilers do this very efficiently), so it may be browser-specific (i.e., fast in some, slow in others). Also, I'm not sure how fast JavaScript is with UTF-strings, so you might try converting a character to its integer code before comparing the values.
for (var index = 0; index < length; index++)
{
var c = str.charCodeAt(index);
switch (c) {
case 0x0009: case 0x000A: case 0x000B: case 0x000C: case 0x000D: case 0x0020:
case 0x0085: case 0x00A0: case 0x1680: case 0x180E: case 0x2000: case 0x2001:
case 0x2002: case 0x2003: case 0x2004: case 0x2005: case 0x2006: case 0x2007:
case 0x2008: case 0x2009: case 0x200A: case 0x2028: case 0x2029: case 0x202F:
case 0x205F: case 0x3000: continue;
}
return false;
}
Another thing to consider is changing for:
for (var index in str)
{
...
}
Edit
Your jsPerf test got some revisions, the current one available here. My code is significantly faster in Chrome 26 and 27, and in IE10, but it's also the slowest one in Firefox 18.
I ran the same test (I don't know how to make jsPerf save those) on Firefox 20.0 on 64-bit Linux and it turned out to be one of the two fastest ones (tied with trimTest, both at about 11.8M ops/sec). I also tested Firefox 20.0.1 on WinXP, but under a VirtualBox (still under 64bit Linux, which might make a significant difference here), which gave 10M ops/sec to switchTest, with trimTest coming second at 7.3M ops/sec.
So, I'm guessing that the performance depends on the browser version and/or maybe even on the underlying OS/hardware (I suppose the above FF18 test was on Win). In any case, to make a truly optimal version, you'll have to make many versions, test each on all browsers, OSes, architectures,... you can get a hold of, and then include in your page the version best suited for the visitor's browser, OS, architecture,... I'm not sure what kind of code is worth the trouble, though.
Since branching is much more expensive than most other operations, you want to keep branches to a minimum. Thus, your sequence of if/else statements may not be very performant. A method which instead uses mostly math would be a lot faster. For example:
One way of performing an equality check without using any branching is to use bitwise operations. One example is, to check that a == b:
a ^ b == 0
Since the xor of two similar bits (ie, 1 ^ 1 or 0 ^ 0) is 0, xor-ing two equal values produces 0. This is useful because it allows us to treat 0 as a "true" value, and do more math. Imagine that we have a bunch of boolean variables represented in this way: nonzero numbers are false, and zero means true. If we want to ask, "is any of these true?" we simply multiply them all together. If any of them were true (equal to zero), the entire result would be zero.
So, for example, the code would look something like this:
function(str) {
for (var i = 0; i < str.length; i++) {
var c = str[i];
if ((c ^ '\u0009') * (c ^ '\u000A') * (c ^ '\u000B') ... == 0)
continue;
return false;
}
return true;
}
The primary reason that this would be more performant than simply doing something like:
if ((c == '\u0009') || (c == '\u000A') || (c == '\u0008') ...)
is that JavaScript has short-circuit boolean operators, meaning that every time the || operator is used, it not only performs the or operation, but also checks to see if it can prove that the statement must be true thus far, which is a branching operation, which is expensive. The math approach, on the other hand, involves no branching, except for the if statement itself, and should thus be much faster.
This creates and uses a 'hash' lookup on the characters of the string, if it detects a non-whitespace then returns false:
var wsList=['\u0009','\u000A','\u000B','\u000C','\u000D',' ','\u0085','\u00A0','\u1680','\u180E','\u2000','\u2001','\u2002','\u2003','\u2004','\u2005','\u2006','\u2007','\u2008','\u2009','\u200A','\u2028','\u2029','\u202F','\u205F','\u3000'];
var ws=Object.create(null);
wsList.forEach(function(char){ws[char]=true});
function isWhitespace(txt){
for(var i=0, l=txt.length; i<l; ++i){
if(!ws[txt[i]])return false;
}
return true;
}
var test1=" \u1680 \u000B \u2002 \u2004";
isWhitespace(test1);
/*
true
*/
var test2=" _ . a ";
isWhitespace(test2);
/*
false
*/
Not sure about it's performance (yet). After a quick test on jsperf, it turns out to be quite slow compared to RegExp using /^\s*$/.
edit:
It appears that the solution you should go with might likely depend on the nature of the data you are working with: Is the data mostly whitespace or mostly non-whitespace? Also mostly ascii-range text? You might be able to speed it up for average test cases by using range checks (via if) for common non-whitespace character ranges, using switch on the most common whitespace, then using a hash lookup for everything else. This will likely improve average performance of the tests if most of the data being tested is comprised of the most common characters (between 0x0--0x7F).
Maybe something like this (a hybrid of if/switch/hash) could work:
/*same setup as above with variable ws being a hash lookup*/
function isWhitespaceHybrid(txt){
for(var i=0, l=txt.length; i<l; ++i){
var cc=txt.charCodeAt(i)
//above space, below DEL
if(cc>0x20 && cc<0x7F)return false;
//switch only the most common whitespace
switch(cc){
case 0x20:
case 0x9:
case 0xA:
case 0xD:
continue;
}
//everything else use a somewhat slow hash lookup (execute for non-ascii range text)
if(!ws[txt[i]])return false;
}
return true;
}

Categories

Resources