I saw JavaScript code which begins with with. That's a bit confusing. What does it do and how can it be used correctly?
with (sObj) return options[selectedIndex].value;
It adds to the scope of the statements contained in the block:
return sObj.options[selectedIndex].value;
can become:
with (sObj)
return options[selectedIndex].value;
In your case, it doens't do a whole lot...but consider the following:
var a, x, y;
var r = 10;
a = Math.PI * r * r;
x = r * Math.cos(PI);
y = r * Math.sin(PI /2);
Becomes:
var a, x, y;
var r = 10;
with (Math) {
a = PI * r * r;
x = r * cos(PI);
y = r * sin(PI / 2);
}
...saves a couple of keystrokes. The Mozilla documentation actually does a pretty good job of explaining things in a little more detail (along with pros and cons of using it):
with - Mozilla Developer Center
the with statement is pure syntactical sugar, but it also can cause some nasty bugs.
See with Statement Considered Harmful for clarification:
If you can't read a program and be confident that you know what it is going to do, you can’t have confidence that it is going to work correctly. For this reason, the with statement should be avoided.
In that with block you dont have to type:
sObj.options[selectedIndex].value
but you can just use:
options[selectedIndex].value
Its the equivalent of
return sObj.options[selectedIndex].value;
With lets you issue a block of statements in the context of a particular object. Therefore all of the statements in the with block are taken to be members of the object in parenthesis.
This can make code more readable at times, but it also can lead to ambiguity, since the variable references can either be with sObj or global.
legitimate uses for javascript's "with" statement :D
I would recommend NOT using this because of performance issues, but what the above means is:
for the object sObj (here presumably a select element), all children and properties referenced on this one (or between following curly braces) treat that as their parent scope.
Your example could be rewritten as...
return sObj.options[selectedIndex].value;
...as the 'with' statement places all related statements in the scope of the supplied object. In this case, it's pretty pointless but, if you were doing lots of operations on 'sObj', then it saves a lot of typing.
Totally ficticious example..
with (sObj)
{
if(options[selectedIndex].value < 10){
options[selectedIndex].value++;
total+ = options[selectedIndex].value;
}
}
But, having said that, it's often the case that saving typing can be achieved in better ways.
It isn't a function (as was indicated in the question title before it was edited) but a statement. It may make more sense if the code sample is formatted like so:
with (sObj){
return options[selectedIndex].value;
}
Regarding what it does (Source)
The with statement establishes the default object for a set of statements. JavaScript looks up any unqualified names within the set of statements to determine if the names are properties of the default object. If an unqualified name matches a property, then the property is used in the statement; otherwise, a local or global variable is used.
Which means that in the code sample, it is first checked if options is a property of sObj. If it is then options refers to sObj.options, otherwise it checks other scopes for a variable defined by the name options
The downside of using a with statement is that it is impossible to know from just glancing at the code what gets accessed. There are other better alternatives as shown in this article
It brings pain and suffering among you and others
Related
In his article on let and const Jason Orendorff states the following:
Crunchy performance details: In most cases, you can tell whether the
declaration has run or not just by looking at the code, so the
JavaScript engine does not actually need to perform an extra check
every time the variable is accessed to make sure it’s been
initialized. However, inside a closure, it sometimes isn’t clear. In
those cases the JavaScript engine will do a run-time check. That means
let can be a touch slower than var.
I decided to try and find an example where this held true and was stumped.
For example, let us look at the following torture scenario:
function doSomethingDumb(q) {
function crash() { ++x; }
q.fn = crash;
crash();
let x;
return crash;
}
Even though the closure is returned at the end of the function, it is guaranteed that the return statement will never execute, even though x is assigned to a member of q (and thus may escape into the wild) x will never be initialized and thus crash will always crash.
In what case would it be impossible to tell whether the variable had been initialized?
Just put that into a condition that is only sometimes fulfilled:
function example() {
if (Math.random() < 0.33) tryIt();
const x = 5;
if (Math.random() < 0.5) tryIt();
function tryIt() {
console.log(x);
}
}
In this example I've chosen a random, but it could as well depend on the function's input parameters. In general, it is not statically decidable whether the statement that accesses the variable will be executed before the initialisation - that's the halting problem. You can write a sophisticated analyser that can determine this for many cases, but there's always a trade off between sophistication and overhead of the analyser.
There is no such thing as slow or fast handle, i.e.: named value, be it a var a const or a let. There's no such thing as "unable to determine" if they are initialized either.
Moreover let/s don't get initialized - they simply get assigned. And since they are made to act similar to 'undeclared variables' they will be assigned their value at runtime and exactly at their point declaration.
Therefore, if a stop error happens occur just one line above the let declaration. It will remain fully undeclared. An you will know it just by looking at the code.
There are similar questions here but they didn't really answer my questions.
So I am curious why we can't declare the same variable twice in Java?
for example:
int a = 4;
int a = 6;
this won't really work in Java.
However in javascript, this actually works:
var a = 1;
var a = 2;
In javascript, people said that the declaration immediately got moved to the start so that it became like this:
var a;
a = 1;
a = 2;
The simple, obvious answer is because the compiler doesn't let you. But now let's go a step further - why would this be desired?
The reason here is that declaring a variable twice is a sign of a mistake. It usually means one of three things:
Your variable names are not specific enough. Perhaps you used int length twice and it barks at you. You probably should make your name more specific to what it holds the length of, for example int originalLength and int extendedLength when copying an array or something.
Your method is too long. Why is your method so long that you need two of the same variable? Chances are you're duplicating code, so consolidate that into a method.
You haven't really thought out your method. This is sort of an extension of number 2, but the truth is you should decide what a method does before you write it. If you're adding a variable that already exists, it probably means that you haven't decided exactly what this method is doing.
Each of those is a major code smell, and is probably the source of bugs down the road. (And not far down the road!) In each of the cases, allowing you to declare a variable twice is going to cause ambiguity that would have been prevented if it stopped you from compiling.
Now, does this mean there aren't cases where it might be nice? Sure. There might be. Maybe you've covered all your bases and you're absolutely sure it's okay to reuse that variable. In that case, just reassign it instead of redeclaring it. Personally, I'd advise against that, but it's your foot to shoot if you want to. :)
You can use the same variable name if the scopes don't overlap, for instance i could have a variable in a private method called "var1" and then in another method have the same thing, these two would not conflict
However since everytime i use "int var1" in the same scope, java is re-declaring the variable, it wont allow it, as it's a conflicting variable name, whereas in java script the declaration happens once, as it's weakly typed
now it has been rectified or improvised in javascript too with the new let keyword
if you try to intialize the same variable name more than once it will throw an error
let a = 4;
let a = 5;
will throw an error in ES6
I often find that I write IF statements which immediately reference the value of the conditional statement. For example, let's say I need to check to see if a string matches a pattern:
if (mystring.match(/mypattern/) {
var mymatch = mystring.match(/mypattern/)[1];
...
};
I suspect that what I'm looking for doesn't exist, but I've wondered whether you can reference the conditional statement's value within the if block, the way you can reference "arguments" within a function. In many cases, of course, I can rewrite it like this:
var mymatch = mystring.match(/mypattern/)[1];
if (mymatch) { ... };
But that's often not possible if there's a series of methods called. For example:
var mymatch = $('.myclass')[0].text().match(/mypattern/)[1];
... that would throw an exception if there were no item [0] on which to call .text(). Is there some convenient shorthand I'm missing out on? Or a better way to organize things? Just curious, really — I'll go on living if the answer is no.
In cases where relevant you can use the fact that the assignment operator returns a value in JavaScript, so for instance you can write things like:
if (assignedTest = testedValue) {
//value of assignedTest is now available
//and conditional will only be executed if true
This could be used if the RHS was compatible or properly set-up but it's also a huge readability concern since it's very easy to confuse the assignment = with comparison ==/===.
If you were particularly motivated to pursue this you could extract this type of functionality into a function that would behave in a reliable way: such as assigning the result of a closure to a named variable, and you could further tune the behavior to do other things (such as optionally evaluating to a different value within the test). Ultimately it would primarily be making a simple structure more complex though.
What are the differences and/or advantages, if any, of using commas when declaring a group of variables rather than semicolons.
For example:
var foo = 'bar', bar = 'foo';
versus
var foo = 'bar';
var bar = 'foo';
I know that if you specify the var keyword on the first variable in the first example it persists across all of the variables, so they both produce the same end result regarding scope. Is it just personal preference, or is there a performance benefit to doing it either way?
No performance benefit, just a matter of personal choice and style.
The first version is just more succinct.
Update:
In terms of the amount of data going over the wire, of course less is better, however you would need a hell of a lot of removed var declarations in order to see a real impact.
Minification has been mentioned as something that the first example will help with for better minification, however, as Daniel Vassallo points out in the comments, a good minifier will automatically do that for you anyways, so in that respect no impact whatsoever.
After reading Crockford and others, I started to chain my variables with comma exclusively. Then later, I really got annoyed by the Chrome DevTools debugger that wouldn't stop at variable definitions with comma. For the debugger, variable definitions chained with comma are a single statement, while multiple var statements are multiple statements at which the debugger can stop. Therefore, I switched back from:
var a = doSomethingA,
b = doSomethignB,
c = doSomethingC;
To:
var a = doSomethingA;
var b = doSomethignB;
var c = doSomethingC;
By now, I find the second variant much cleaner, not to mention its advantage of solving the debugger issue.
The "less code through the wire" argument is not persuasive, as there are minifiers.
I prefer the var-per-variable notation:
var a = 2
var b = 3
because the other comma-instead-of-another-var notation have these three shortcomings:
1. Hard to maintain
Consider this code:
var a = 1,
b = mogrify(2),
c = 3
But hey, what does the mogrify do? Let's print b to find out:
var a = 1,
b = mogrify(2),
console.log(b)
c = 3
breaks stuff
2. Hard to read
The var in the begging of the line clearly communicates that there will be a new variable initiated.
var get_all_unicorn_promise = db.get_all_unicorns((unicorn) => {
unicorn.legs.map((leg) => {
leg.log('yes')
})
}).sort(),
c = 3
What the hell is the c = 3 doing there right?
3. Not consistent
Consider this:
var a = 1,
b = 2,
c = 3
With var-per-variable every declaration follow the same structure. With comma-instead-of-another-var the first variable is declared in different way than others. If you decide to, say, move the first variable inside a for cycle, you will have to add var to the middle of declarations
Other than preference, it seems like majority of notable projects use the var-per-variable notation
I agree with the other answerers that this is mainly a matter of personal style. But to bring an "Authoritative" opinion into the discussion, this is what Douglas Crockford says on the website of the popular JSLint tool:
But because JavaScript does not have block scope, it is wiser to declare all of a function's variables at the top of the function. It is recommended that a single var statement be used per function. This can be enforced with the onevar option.
As others have noted, it is a style preference. JSLint might tell you to only have one var per function (if you use the "Good Parts"). Thus if using JSLint to check your code (not a bad idea, IMHO), you'll end up using the first format more than the latter.
On the other hand, the same author, Douglas Crockford, says to put each variable in its own line in his coding conventions. So you may want to uncheck the "All one var per function" checkbox in JSLint if you use it. ;-)
I don't think there's any noticeable difference, as far as I'm concerned it's just personal preference.
I hate having multiple var declarations so I usually do:
var
one
,two
,three
,four
;
As it's shorter and arguably more readable, no var noise to look at.
Since I don't see any references to it, here is a link to the ECMA-262 specification, which is the underlying spec for JavaScript. The grammar from that page says:
12.2 Variable Statement
Syntax
VariableStatement :
var VariableDeclarationList ;
VariableDeclarationList :
VariableDeclaration
VariableDeclarationList , VariableDeclaration
VariableDeclarationListNoIn :
VariableDeclarationNoIn
VariableDeclarationListNoIn , VariableDeclarationNoIn
VariableDeclaration :
Identifier Initialiseropt
VariableDeclarationNoIn :
Identifier InitialiserNoInopt
Initialiser :
= AssignmentExpression
InitialiserNoIn :
= AssignmentExpressionNoIn
What you can glean from this is using commas or not doesn't matter. Either way, it ends up being parsed as a VariableDeclaration and is treated exactly the same. There should be no difference to how the script engine treats the two declarations. The only differences would be ones already mentioned in other answers - saving more space and practically immeasurable differences in the amount of time it takes to apply the grammar to find all the VariableDeclarations when the script is compiled.
The first saves a few characters--so there is a very small saving in terms of the JS filesize and therefore bandwidth consumption. The only time this would become noticable would be in extreme cases.
I prefer the second version (each has its own var). I think that's because I come from a C++ background. In C++, you can declare variables like you do in your first example, but it is frowned upon (it easily leads to mistakes when you're trying to create pointers that way).
If you are minifying your javascript, there is a fairly large benefit:
var one, two, three, four;
becomes
var a, b, c, d;
Where as
var one;
var two;
var three;
var four;
becomes
var a;
var b;
var c;
var d;
That's an additional three instances of var, which can add up over time.
See The "A List Apart" article series "Better Javascript Minification" Part 1 and Part 2
I've always wondered why Javascript has the global Math object instead of giving numbers their own methods. Is there a good reason for it?
Also are there any drawbacks (other than efficiency) to doing something like this?:
Number.prototype.round = function(){
return Math.round(this);
};
Just to make clear, I understand that constants like π need somewhere and functions that are applied on more than one number like min/max. The question was mainly concerning methods which only effect a single number such as round, abs, sin, pow, etc.
The reason for the Math object is simple: "because Java does it". Not the best of reasons, but here we are. I guess things made more sense back then, before Douglas Crockford started his campaign to suppress half the language*. Originally you were "allowed", or meant, to do things like this:
with (Math) {
var n = min( round(a) * round(b), sqrt(c) );
var result = exp( n + d );
}
The drawback to extending Number.prototype is that someone else might do the same thing. Or worse, for example, define Number.prototype.round as a symmetrical rounding function.
If you are looking for ways to make your life easier, why stop there? Why not simply include Math functions as global functions?
var m = 'abs acos asin atan atan2 ceil cos exp floor log max min ' +
'pow random round sin sqrt tan PI').split(' ');
for (var i=0,l=m.length; i<l; i++) {
window[ m[i] ] = Math[ m[i] ];
}
This will drop all the math functions into the global scope, effectively allowing you to stop typing "Math." Ask yourself: Is there any real difference between extending Number and extending window with these functions?
* Before you flame me: The Crockford comment is not meant to be taken too seriously. I do agree with him that with is very dangerous in an implicit global environment.
There is no drawback in extending Number.prototype other than confusing other people. What's the point? What is better in using value.round() instead of Math.round(value)?
There are several good reasons for the Math object:
It works for non-numbers, too: Math.round("5") works whereas value.round() won't work when value is a string (for example, the value of a textbox)
Some members of the Math object don't belong to a "primary" number value, like Math.min() or Math.max(). Or do you want to use it like a.max(b)?
Other members are global and do not belong to a specialized number. Examples are constants like Math.PI or the function Math.random().
Try doing 123.round();
Your javascript console will throw a few hundred of errors to your eyes :P, nah ...
You can do:
Number.prototype.x then: (123).x(); but never 123.x();
I think Math is more than set of Number methods. It's usage wider. Say, using NumberVariable.PI can be confusing. Same with random numbers generation.
Also I think extending number is OK, because it's the part of JS nature. Maybe someone will correct me if I am wrong here.
I believe calling it this way works as well, since Number's prototype functions work just like every other Object's prototype functions do:
5.5["round"]();
//should return 6
So, the conversation on whether its a good idea or not aside, you can do this fine.
You can do 123.x() but the interpreter for js is broken (as it doesn't interpret the dot as a message dispatch)
Weirdly, you can use 123 .x() (with a space between the number and the dot) instead, and it'll work.
123..also works but that's because you've effectively made a decimal and then dispatching to it
(typeof 123.) === 'number') // true
Try:
Number.prototype.times = function(other) { return this * other }; 3 .times(5);
in the console.
My view on this is that if you do the proper checks as to not overwrite native functionality, name with understanding of native naming standards and it makes your code more readable and manageable, then make your code comfortable and convenient.
if (Number.prototype.round == null)
Number.prototype.round = function() { return Math.round(this); }
AS for using this, because of the nature of javascript, I believe the best way to do this is by:
Wrapping the number in a variable instead of a simple static value (Most often the case)
nNum.round();
Wrapping the simple static value in parentheses :
(123).round();
Calling using square bracket notation
123["round"].call();
You can do this
Number.prototype.round = function() {
return Math.round(this.valueOf());
};
https://www.w3schools.com/jsref/jsref_prototype_num.asp