What is "excessive trickness"? - javascript

After reading Douglas Crockford's "JavaScript: The Good Parts" and Stoyan Stevanov's "JavaScript Patterns," I'm trying to determine exactly what 'excessive trickiness' means. They both say that this occours when using either ++ or -- in your code, but can't find a firm definition for this term, either within SO or via a Google search. Any ideas?

You can hear it from Crockford himself here: http://www.youtube.com/watch?feature=player_detailpage&v=47Ceot8yqeI#t=4140s
The simple answer is that ++ and -- act on a variable, and usually do it at the same time as you're doing something else to that variable. For example, can you quickly decide what this does?
y += x++ + ++y; // what is y now?
More StackOverflow discussion: Why avoid increment ("++") and decrement ("--") operators in JavaScript?

It's about the little tricks that are built-in. For example, avar++ is an alias for avar = avar + 1.
JavaScript is filled with operators and other things that make programming easier, but they are just tricks. That's probably what he means.
Also, as Jonathan pointed out: Why avoid increment ("++") and decrement ("--") operators in JavaScript?

Excessive trickiness is subjective. Because of that, there's no firm definition for it.
Some would say the C famous string copy code (while (*p++ = *q++);) is excessively tricky, some would say it's not.

Here is a fairly lengthy discussion with links:
Why avoid increment ("++") and decrement ("--") operators in JavaScript?
I think part of the idea is that when using those operators anywhere but with a single variable on a single line, they become confusing to anyone not in the developer's head.

Related

Call JS Math functions without writing Math.__ every time?

I have some code that uses JavaScript’s Math functions quite a lot, to the point that I’d much rather be writing things like exp(cos(PI/2)) instead of Math.exp(Math.cos(Math.PI/2)), which gets ugly and unreadable fast. Even an alias like m. would be clutter. To that extent, I need a simple bit of header code to enumerate over Math and pull its entries into the current scope.
Good news is, standing on the shoulders of Stack Overflow giants, I’ve built an elegant solution to share with the world!! 🥳 Here it is:
// Import all Math numbers and functions to the current (global) scope.
for (let name of Object.getOwnPropertyNames(Math))
globalThis[name] = Math[name]
console.log( exp(cos(PI/2)) ) // = 1
Codepen
I’m very happy with it, posting it here to give back to the community and to see if anyone has improvements! 💞 It truly just feels so much cleaner now, like how it should’ve always been. Math functions deserve to be global!
Posted above!
// Import all Math numbers and functions to the current (global) scope.
for (let name of Object.getOwnPropertyNames(Math))
globalThis[name] = Math[name]
console.log( exp(cos(PI/2)) ) // = 1
Codepen

"".constructor vs 2.constructor in Javascript

I've just been experimenting with a little bit of Javascript and got to the point of understanding the inheritance concept.
I am able to get an evaluation for the below code:
"".constructor
//which evaluates to function String()
Ok Cool. But why is it that when I do the below code, there is an error?
2.constructor
//returns an error
Basically both are primitives right?, so should there not be an error for the empty string as well?
Hope someone can give me a good explanation that will help me learn this one better. Looking forward to your support.
You could spend another dot for the decimal point.
console.log(2..toString());
console.log(2.2.toString());
Or wrap the value in parenthesis.
console.log((2).toString());
console.log((2.2).toString());

Is there a good reason to avoid FOR loops without a final-expression in JS?

Is it a bad habit to write reverse loops as:
for (i = N; i--;)
in order to access (N-1) to 0
If so, why? jsLint certainly doesn't like it.
There's no technical reason that this won't work. However, it clearly has readability issues since someone had an immediate "well that won't work!" reaction.
This is the kind of issue that the jQuery team struggles with – whether to use novel constructs that save bytes at the expense of clarity and maintainability. It really comes down to whether it's worth 1 or 3 bytes of savings:
for(var i=9;i--;)
var i=9;while(i--)
for(var i=9;i>0;i--)
In this case, probably not.
It is less readable, without your explanation it would take me few seconds to understand what the loop does. Why not simply:
while(i-- > 0)
?
Did you consider readability? You may very well understand it yourself, but other developers might get confused since the parts of the for "idiom" are usually named as:
for ([initialization]; [condition]; [final-expression])
While the condition can technically be any expression, your version does not conform to this idiom, since the "condition" part you use does more than just defining a condition - it sneakily decrements i as well.
"Is it a bad habit to write reverse loops as:"
for (i = N; i--;)
That's a matter of opinion, but it's effectively a reverse while with initialization, so in my opinion it's not a "bad habit". It's just a coding style.
The specification makes the parts of a for optional to give the developer that flexibility.
"jsLint certainly doesn't like it."
Who cares. You're not bound to follow the opinions of jsLint.
The answers would be very subjective I guess. I don't think it is a bad habit but I do find it aesthetically unpleasing. This can be expressed more elegantly as:
for (i = N - 1; i >= 0; i--) {
// do something here.
}
// And if it is really important that i should be 0 here
// as it is in your original code.
i = 0
This code is easier on our brain while browsing a lot of code that happens to contain this.
Yes. There is a good reason. Readability.

How do languages handle side effects of compound operators?

Assume such situation:
int a = (--t)*(t-2);
int b = (t/=a)+t;
In C and C++ this is undefined behaviour, as described here: Undefined behavior and sequence points
However, how does this situation look in:
JavaScript,
Java,
PHP...
C#
well, any other language which has compound operators?
I'm bugfixing a Javascript -> C++ port right now in which this got unnoticed in many places. I'd like to know how other languages generally handle this... Leaving the order undefined is somehow specific to C and C++, isn't it?
According to the ECMA Script specification, which I believe javascript is supposed to conform to, in multiplication and addition statements, it evaluates the left hand side before evaluating the right hand side. (see 11.5 and 11.6). I think this means that the code should be equivalent to
t = t - 1;
int a = t * (t - 2);
t = t / a;
int b = t + t;
However, you should not always trust the specification to be the same as the implementation!
Your best bet in confusing cases like this is to experiment with various inputs to the ambiguous lines of code in the original operating environment, and try to determine what it is doing. Make sure to test cases that can confirm a hypothesis, and also test cases that can falsify it.
Edit: Apparently most JavaScript implements the 3rd edition of ECMAScript, so I changed the link to that specification instead.
Practically speaking, if you have to ask or look up the rules for an expression, you shouldn't be using that expression in your code. Someone else will come back two years from now and get it wrong, then rewrite it and break the code.
If this was intended as a strictly theoretical question I unfortunately can't offer details regarding those other languages.
For javascript the following article should help.
This article clearly states whether a particular combination of
a OP b OP c goes from left-to-right and in which order.
I'm don't know about the other languages.
However, how does this situation look in: JS, Java, PHP, C#...
To be perfectly candid, int a = (--t)*(t-2); int b = (t/=a)+t; looks like crap.
It's nice to have fancy code that can be all pretty and elitist, but there's absolutely no need for it. The solution for every language when confronted with code like this is to add a couple more semi-colons (unless you're dealing with python):
--t;
int a = t * (t-2);
t /= a;
int b = t + t;
-or-
int b = t * 2;
-or-
int b = t << 1;
//whichever method you prefer
If a different order of operations is desired, the adjust the lines accordingly. If you're trying to fix old buggy code, fix the code, don't just re-implement someone else's spaghetti.
Edit to add:
I realized I never specifically answered the original question:
How do languages handle side effects of compound operators?
Poorly.

Good resources for extreme minified JavaScript (js1k-style)

As I'm sure most of the JavaScripters out there are aware, there's a new, Christmas-themed js1k. I'm planning on entering this time, but I have no experience producing such minified code. Does anyone know any good resources for this kind of thing?
Google Closure Compiler is a good javascript minifier.
There is a good online tool for quick use, or you can download the tool and run it as part of a web site build process.
Edit: Added a non-exhaustive list of tricks that you can use to minify JavaScript extremely, before using a minifier:
Shorten long variable names
Use shortened references to built in variables like d=document;w=window.
Set Interval
The setInterval function can take either a function or a string. Pass in a string to reduce the number of characters used: setInterval('a--;b++',10). Note that passing in a string forces an eval invokation so it will be slower than passing in a function.
Reduce Mathematical Calculations
Example a=b+b+b can be reduced to a=3*b.
Use Scientific Notation
10000 can be expressed in scientific notation as 1E4 saving 2 bytes.
Drop leading Zeroes
0.2 = .2 saves a byte
Ternery Operator
if (a > b) {
result = x;
}
else {
result = y;
}
can be expressed as result=a>b?x:y
Drop Braces
Braces are only required for blocks of more than one statement.
Operator Precedence
Rely on operator precedence rather than adding unneeded brackets which aid code readability.
Shorten Variable Assignment
Rather than function x(){a=1,b=2;...}() pass values into the function, function x(a,b){...}(1,2)
Think outside the box
Don't automatically reach for standard ways of doing things. Rather than using d.getElementById('p') to get a reference to a DOM element, could you use b.children[4] where d=document;b=body.
Original source for above list of tricks:
http://thingsinjars.com/post/293/the-quest-for-extreme-javascript-minification/
Spolto is right.
Any code minifier won't do the trick alone. You need to first optimize your code and then make some dirty manual tweaks.
In addition to Spolto's list of tricks I want to encourage the use of logical operators instead of the classical if else syntax. ex:
The following code
if(condition){
exp1;
}else{
exp2;
}
is somewhat equivalent to
condition&&exp1||exp2;
Another thing to consider might be multiple variable declaration :
var a = 1;var b = 2;var c = 1;
can be rewritten as :
var a=c=1,b=2;
Spolto is also right about the braces. You should drop them. But in addition, you should know that they can be dropped even for blocks of more expressions by writing the expressions delimited by a comma(with a leading ; of course) :
if(condition){
exp1;
exp2;
exp3;
}else{
exp4;
exp5;
}
Can be rewritten as :
if(condition)exp1,exp2,exp3;
else exp4,exp5;
Although it's not much (it saves you only 1 character/block for those who are counting), it might come in handy. (By the way, the latest Google Closure Compiler does this trick too).
Another trick worth mentioning is the controversial with functionality.
If you care more about the size, then you should use this because it might reduce code size.
For example, let's consider this object method:
object.method=function(){
this.a=this.b;
this.c++;
this.d(this.e);
}
This can be rewritten as :
object.method=function(){
with(this){
a=b;
c++;
d(e);
}
}
which is in most cases signifficantly smaller.
Something that most code packers & minifiers do not do is replacing large repeating tokens in the code with smaller ones. This is a nasty hack that also requires the use of eval, but since we're in it for the space, I don't think that should be a problem. Let's say you have this code :
a=function(){/*code here*/};
b=function(){/*code here*/};
c=function(){/*code here*/};
/*...*/
z=function(){/*code here*/};
This code has many "function" keywords repeating. What if you could replace them with a single(unused) character and then evaluate the code?
Here's how I would do it :
eval('a=F(){/*codehere*/};b=F(){/*codehere*/};c=F(){/*codehere*/};/*...*/z=F(){/*codehere*/};'.replace(/function/g,'F'));
Of course the replaced token(s) can be anything since our code is reduced to an evaluated string (ex: we could've replaced =function(){ with F, thus saving even more characters).
Note that this technique must be used with caution, because you can easily screw up your code with multiple text replacements; moreover, you should use it only in cases where it helps (ex: if you only have 4 function tokens, replacing them with a smaller token and then evaluating the code might actually increase the code length :
var a = "eval(''.replace(/function/g,'F'))".length,
b = ('function'.length-'F'.length)*4;
alert("you should" + (a<b?"":" NOT") + " use this technique!");
In the following link you'll find surprisingly good tricks to minify js code for this competition:
http://www.claudiocc.com/javascript-golfing/
One example: (extracted from section Short-circuit operators):
if (p) p=q; // before
p=p&&q; // after
if (!p) p=q; // before
p=p||q; // after
Or the more essoteric Canvas context hash trick:
// before
a.beginPath
a.fillRect
a.lineTo
a.stroke
a.transform
a.arc
// after
for(Z in a)a[Z[0]+(Z[6]||Z[2])]=a[Z];
a.ba
a.fc
a.ln
a.sr
a.to
a.ac
And here is another resource link with amazingly good tricks: https://github.com/jed/140bytes/wiki/Byte-saving-techniques
First off all, just throwing your code into a minifier won't help you that much. You need to have the extreme small file size in mind when you write the code. So in part, you need to learn all the tricks yourself.
Also, when it comes to minifiers, UglifyJS is the new shooting star here, its output is smaller than GCC's and it's way faster too. And since it's written in pure JavaScript it should be trivial for you to find out what all the tricks are that it applies.
But in the end it all comes down to whether you can find an intelligent, small solution for something that's awsome.
Also:
Dean Edwards Packer
http://dean.edwards.name/packer/
Uglify JS
http://marijnhaverbeke.nl/uglifyjs
A friend wrote jscrush packer for js1k.
Keep in mind to keep as much code self-similar as possible.
My workflow for extreme packing is: closure (pretty print) -> hand optimizations, function similarity, other code similarity -> closure (whitespace only) -> jscrush.
This packs away about 25% of the data.
There's also packify, but I haven't tested that myself.
This is the only online version of #cowboy's packer script:
http://iwantaneff.in/packer/
Very handy for packing / minifying JS

Categories

Resources