I'm always on the lookout for new ways to be more efficient.
And JavaScript is always full of pleasant surprises.
1. Transform the arguments object into an array.
The arguments object is an Array-like object accessible inside functions that contains the values of the arguments passed to that function.
But it's not like other arrays, we can access the values and we can get the length, but no other array methods can be used on it.
Luckily, we can just convert it into a regular array:
var argArray = Array.prototype.slice.call(arguments);
2. Sum all the values from an array.
My initial instinct was to use a loop, but that would have been wasteful.
var numbers = [3, 5, 7, 2];
var sum = numbers.reduce((x, y) => x + y);
console.log(sum); // returns 17
3. Short circuit conditionals.
We have the following code:
if (hungry) {
goToFridge();
}
We can make it even shorter by using the variable with the function:
hungry && goToFridge()
4. Use logical OR for conditions.
I used to declare my variables at the start of my function just to avoid getting undefined if anything went unexpectedly wrong.
function doSomething(arg1){
arg1 = arg1 || 32; // if it's not already set, arg1 will have 32 as a default value
}
5. Comma operator.
The comma operator (,) evaluates each of its operands (from left to right) and returns the value of the last operand.
let x = 1;
x = (x++, x);
console.log(x);
// expected output: 2
x = (2, 3);
console.log(x);
// expected output: 3
6. Using length to resize an array.
You can either resize or empty an array.
var array = [11, 12, 13, 14, 15];
console.log(array.length); // 5
array.length = 3;
console.log(array.length); // 3
console.log(array); // [11,12,13]
array.length = 0;
console.log(array.length); // 0
console.log(array); // []
7. Swap values with array destructuring.
The destructuring assignment syntax is a JavaScript expression that makes it possible to unpack values from arrays, or properties from objects, into distinct variables.
let a = 1, b = 2
[a, b] = [b, a]
console.log(a) // -> 2
console.log(b) // -> 1
8. Shuffle elements from array.
Every day I'm shufflin'
Shufflin', shufflin'
var list = [1, 2, 3, 4, 5, 6, 7, 8, 9];
console.log(list.sort(function() {
return Math.random() - 0.5
}));
// [4, 8, 2, 9, 1, 3, 6, 5, 7]
9. Property names can be dynamic.
You can assign a dynamic property before declaring the object.
const dynamic = 'color';
var item = {
brand: 'Ford',
[dynamic]: 'Blue'
}
console.log(item);
// { brand: "Ford", color: "Blue" }
10. Filtering for unique values.
For all you ES6 fans out there, we can create a new array containing only the unique values by using the Set object with the Spread operator.
const my_array = [1, 2, 2, 3, 3, 4, 5, 5]
const unique_array = [...new Set(my_array)];
console.log(unique_array); // [1, 2, 3, 4, 5]
Closing thoughts.
Being responsible is far more important than being efficient.
Your website NEEDS to work in all browsers.
You can use Endtest or other similar tools to make sure it does.
What about you? Do you have any JavaScript tips or tricks to share?
Top comments (43)
Eh, I hate to be a jerk, but this is full of really poor practices. To be honest, I stopped after 2 or 3 because they're teaching bad lessons.
Examples:
arguments
should be deprecated in favor of rest parameters.0
in this case as the second argument to reduce.Please, beginners reading through this, don't do most of these things.
I appreciate that you took the time to write a comment.
You remind me of a friend that has been waiting for 2 years to get some experience in order to give advice to beginners.
He just keeps giving strange advice and the junior devs simply ignore him.
The MDN webdocs just provide the following note:
If you're writing ES6 compatible code, then rest parameters should be preferred.
I never said that you should write all of your code with the tricks that I used, they're just presented as an interesting read.
It seems you just missed the point completely.
Nice tips for any of those contests to do things in the few number of lines, but I'm with David Hunt, this is almost a must set of error lint rules. In enterprise apps, never sacrifice readability for fewer lines of code without a very, very good reason.
If you don't like his comments, I might say why did the world need another "10 javascript..." repeat article?
"You remind me of a friend that has been waiting for 2 years to get some experience in order to give advice to beginners."
Your friend is right. When I see advice like the ones in the article, I usually say "I hope your doctor and your lawyer are better at their job than this."
I've handled over a 100 front-end interviews for my employers and code like that would seriously hurt candidates chances.
It's pretty obvious that these tricks do not make your JavaScript more readable, they're not supposed to help with readability.
The purpose is to show the reader that things in JavaScript can also work this way.
I'm sure you're an expert in the bleeding edge technology that your employer is using and you're really good at those interviews, but it seems you just missed the point of this article.
merriam-webster.com/dictionary/pra...
Practical:
"The purpose is to show the reader that things in JavaScript can also work this way." - even you yourself describe this precisely as theoretical. Practical is "here is how this should be done".
Look, I would not be commenting here, if I haven't seen over and over again junior devs reading such articles and rushing to use tricks from them everywhere. The best course of action for you would be to remove half of the tricks you've written, since only harm can come out of them. The question is - are you willing to admit you were wrong or is your ego more important to you than your readers?
Actually, leaving out the starting value is fine as long as your array is not empty. When you do that, it will use the first element as the starting value. I think in general it is better to be explicit and provide one though.
Nothing wrong with the reduce here.
You can skip the initial value in your reduce, but now you have to check that the array length is greater than zero.
So you've introduced a serious bug in your application to save typing two characters.
Also as others have pointed out use of var is discouraged, use of arguments keyword is discouraged and a few other bad practices.
Enough already! I can't stand this very kind of pseudo-articles. Just keep your knowledge to yourself until you have something that is actually worth posting and is in some way innovative. DEVto and Medium are nowadays full of totally worthless posts made just to get the attention, not the knowledge. I mean what is this? Attention seeking? A boast?
Plus, at this point, all there is to read here is top-10 lists. This is not Youtube.
Agreed with some other comments that there are quite a few issues here.
1- Better to use the standardized
Array.from()
which is designed for use with array-like objects such asarguments
. Better yet, rest parameters should be used when possible, since they are more explicit thanarguments
.3- Perfectly valid syntax, but using the
if
is much more clear and explicit about the intention.4- Using default parameters is not only more explicit, but it also avoids issues when you want a falsy value to be possible (the code in the article will not allow
0
for example, but that might be completely valid)5- Not sure there is actually a practical application of this. I sound like a broken record at this point, but since most people do not know this, it makes the code much more difficult to read. Always be explicit.
6-
array.slice()
is more clear about the intentions.10- This is a great one. I use it
That closing thought is extremely important, unfortunately most of the tricks here are ultimately not responsible.
Sorry to point this out, but about half of this advice are bad.
3
hungry && goToFridge()
- no. Your code is written once and then read 10 times. This makes it harder to read.4 And now you can't have 0... Use default args.
If you are dealing with variables - use nullish coalescing operator.
5 'Coma operator' - don't use it as described ever. It is a constant source of bugs.
6 'Using length to resize an array' - try avoiding this. It is a hack that hides intentions and leads to bugs.
P.S.
1
Hi Zander
I am the editor of InfoQ China which focuses on software development. We like your article and plan to translate this into Chinese.
Before we translate and publish it on our website, I want to ask for your permission first! This translation version is provided for informational purposes only, and will not be used for any commercial purpose.
In exchange, we will put the English title and link at the end of Chinese article. If our readers want to read more about this, he/she can click back to your article.
Thanks a lot, hope to get your help. Any more question, please let me know.
Hi,
Yes, you have my permission to do that.
Thank you for asking.
Please don't remove any part from the article when you translate it.
infoq.cn/article/fgeB0Bu3jpAzmba9ro3x
any questions pls let me know, thx
Sure, thx a lot, will post our translation link here after we publish it.
Love seeing the "weird" parts of JavaScript. Can you elaborate on the Shuffle, where the '- 0.5' comes from?
The
sort
function sorts before/after by checking negative vs positive numbers (0 means equal). Sincerandom
gives back anything between0 to 1
you would never have a negative number. So you just simply substract-0.5
.I think this is wrong though?
Since
random
is exclusive of 1, you're going to be slightly biased towards negatives, and thus not totally uniform (assuming that's the goal which 0.5 implies), right?Maybe it should be
Math.floor(Math.random() + 1) - 0.5
I think...
Your proposed code always returns
0.5
since you floor a number x with1 <= x < 2
which floored always gives1
and therefore1 - 0.5 = 0.5
so I do not think your solution would lead to anything useful in this case since it would not shuffle at all :)The JS spec says:
That means we can trust the uniformity of it EXCLUDING the exact number
1
but including0
. So your argument is that we miss out on non-uniformity because it can only reach0.99999999999999999
but in fact from a mathematical perspective this is the same number as1
. Not just mathematically but also in fact0.99999999999999999 == 1
in JavaScript. Even if it was not (just theoretically) then the missing bit would be so extremely small that it would essentially become insignificant.Oops, I should have said
Math.floor(Math.random() * 2)
But I'm still not convinced of your argument. I agree that it is most likely insignificant, (considering the PRNG is essentially a black box and I don't even know if it is a standard implementation across all engines, and if it is it probably is not uniform to begin with). Add to the fact that we are dealing with FP and not continues numbers also muddies the water. But all else being equal, we would have a bias because the random function is not inclusive. But then again on a second though, the sort function would also return the same for 0.5 as it would for 0.5 + ε so that effectively gives you a uniform range of values.
For what it's worth, I tried running it in V8 (billions of times) but couldn't discern any patterns either way (but I was just seeing if the average was above or below 0 and logging the output; it would be interesting to investigate it further with proper statistical analysis.)
Hey Zach. Maybe if you "mistrust" it then you rather first read the JS specs. The Engines are not allowed to interpret the distribution differently since they are spec based.
Your arguments are, sorry to say, invalid since the uniformity for the random function is given and due the to equalness of
0.99999999999999999 == 1
and the INEQUALNESS of0.00000000000000001 == 0
. So there is your missing bit. Your so-called Epsilon does not exist since this is there is no more Epsilon than this. I just wrote the minimum and maximum numbers theMath.random
returns.Also again you probably meant with your example
Math.floor(Math.random() * 2) - 1
since you are trying to have a "real" integer 1 inclusion but this does not change anything since from a mathematical perspective the distribution does not change with a factor for this sample since the factor is strictly linear.Also if you have a "general" mistrust in the
Math.random
function then this is totally fine because it is "not really" random. There is the WebCrypto API which tries to provide way better randomized values.I'm not sure what you mean by check the spec (or "mistrust")? There is no PRNG spec, it is entirely up to the engine. That means it depends on the environment you run your code in. For this discussion it is a black box and different black boxes have different implementations. Different implementations will have different uniformity. That alone makes this whole discussion pointless.
Second, you are still acting like we are working with continuous numbers. We are not. There is a finite set of numbers in JavaScript between 0 and 1. You could enumerate them like {a, b, c, d, ...}.
It's easy to create a general case where you have X numbers in your set. If you split the set in half, the halfs will either be equal (cardinality wise) or not (depending if X is even or odd). If they are not equal then any time you uniformly choose a number from the entire set, you will choose the larger set more often.
If you deny this then you are denying simple math. And this is exactly my point. This changes if you are dealing with continuous numbers (but we are not). We are splitting a finite set of numbers into two sets and choosing a set based on if it contains a number or not.
I am not sure what you are trying to say since it was about the uniformity and you questioned first the approach in itself since the
0.00000000000000001
is missing because1
is never reached. So I tried simply telling you that1
is reached and therefore the initial argument does not count since even though the exact number0.99999999999999999
is mathematically not the same (as it does not have infiinite9
) it is in fact in JavaScript. But in fact0.9repeating
is the same as 1 mathematically en.wikipedia.org/wiki/0.999...Then you were providing something as static
0.5
and then providing a solution that just does the same as what the author proposed but times2
and therefore not really changing anything but the overall interval.This feels like you are jumping into more and more topics also because you compare Maths with JS but JS only has a subset of what actual Maths provide (e.g. precision wise) so ACTUAL maths 1:1 compared to JS do not really fit since not all theories apply exactly the same.
When I was talking about "mistrust" I was talking about the fact that you mistrust the uniformity of the PRNG in
Math.random
because you say that the approach of the author shall not be used although I try to argue that for shuffling an array it is very much helpful and sufficient.Also you could actually check the sourcecode of V8. If you are coding for browsers you can check WebKit, V8 and SpiderMonkey. For node.js you can do the same.
E.g. for WebKit trac.webkit.org/browser/webkit/
By checking those sourcecodes you could decide if they fit your - apparently weirdly rare - use-cases. Or in other words: What use-case are you trying to solve so maybe that helps better treating the problem that you apparently have.
So I am unsure what problem you are trying to solve right now or if you are just trying to rant to be honest.
If you want a better random generator then go for the WebCrypto API. I am out and will not longer respond to this weirdly side-escalating discussion.
First, this is all hypothetical. I already agreed that is doesn't matter.
But you are wrong in your premise. Assuming the PRNG was perfectly uniform, the fact that 1 is not included in the interval DOES AFFECT the shuffling. It doesn't matter that 0.999999 = 1.
Let's make the assumption that the PRNG is ideally uniform (otherwise nothing else matters).
Then let's make a list of every number that can be represented in JavaScript as an IEEE754 double precision FP number (which is what Math.random() returns)
The set is written in hex, but it starts like
0x0000000000000001 = 4.94065645841246544176568792868E-324
0x0000000000000002 = 9.88131291682493088353137585736E-324
...
0x3FEFFFFFFFFFFFFF = 9.99999999999999888977697537484E-1 (closest number to 1 before 1)
0x3FF0000000000000 = 1
set a = {
0x0000000000000001, 0x0000000000000002, 0x0000000000000003, 0x0000000000000004, ....
0x3FEFFFFFFFFFFFFF
}
set b = {
0x0000000000000001, 0x0000000000000002, 0x0000000000000003, 0x0000000000000004, ....
0x3FEFFFFFFFFFFFFF, 0x3FF0000000000000
}
Do you see how set a excludes 1, and set b includes 1?
Now split each set into two 1/2 sets where each half set as equal cardinality (if possible)
Do you agree that the two halves of set a are different than the two sets of set b?
Now, randomly pick any number from the entire sample space. Then choose the half set from a that contains the number, and choose the half set from b that contains the number. Guess what, you will pick the 1/2 set with the more numbers more times than the half set with the less numbers.
This is why it matters if 1 is included. You keep saying that 0.99999999=1 but that doesn't mean anything. In fact, it less than meaningless because all you are saying is the decimal value 0.99999999 is represented as 1 as a 64-bit FP number. You are conflating the decimal representation with the in-memory representation. We are dealing with finite sets of discrete numbers.
My original argument was that sorting using the described method will result in a biased sort.
I have since said that it doesn't matter because even assuming the PRNG was perfectly uniform the bias would be insignificantly small, and even more so, it doesn't matter because the PRNG is a black box that is most likely far from perfectly uniform.
But my original statement is correct. Excluding 1 changes the behavior, unless that change is accounted for.
And you are most likely correct that my solution was not an improvement. The first one was 100% wrong, the second might not do anything because it still has the built flaw of not including 1 in the original random number. But my point wasn't to solve the problem, just to show that it won't result in a uniform sort.
I would just use
Array.from(arguments)
but still can't see a real scenario that you would need to use array functions in the arguments listHere your function will fail if the passed value is
0
.Array.prototype.slice.call
is very much a workaround for just callingArray.from
if you'd really like to do it explicitly instead of using the...
operator.That shuffle function is great!
I think the best way to practice javascript is -
Some comments may only be visible to logged-in visitors. Sign in to view all comments.