Thomas said:
That there is no need to rip declaration and initialization
apart is not open for debate;
That is a very loaded expression. It is debatable whether declaration
and initialisation were ever together in the first place, and so whether
separating them would be 'ripping' them apart. Of course if they were
never together to start with any absence of a need to separate them is
not open for debate, it is just irrelevent.
The absence of need may be a fact. As may be that absence not being open
for debate. But if declaration and initialisation were never really
together to start with then those facts are just the trivial
consequences of the act of separation being superfluous.
supported by the language specification and
its implementations.
The specification states that variable declarations are acted upon
during variable initialisation, prior to any code in the execution
context being executed, and that assignments (and so what is being
spoken of as initialisation here) are handled when the assignment
expression is evaluated during the execution of the code for the
execution context. This makes the two actions chronologically distinct,
with all of the first (declarations) being handled before any of the
latter (initialisations).
That this makes maintenance a lot harder is also not merely
an opinion.
No, that is a matter of opinion. Doing nothing other than separating
declarations form initialisations may make maintenance harder but in
realty the alternative is to formally declare all local variables at the
start of the containing function's body. This has the advantage that if
you want to verify that a variable used has been declared, or to insure
that it only has one declaration (because javascript could act on each
and every declaration for the same variable, which would make
re-declaring wasteful), then you only have to go to one location to
look. Reducing the time to find a declaration is a plus for maintenance.
Common sense already tells you that you would have to watch for
that all identifiers of variables that you use are declared a
number of lines before they are actually used; depending on the
complexity of the code, that may be a dozen, maybe a hundred lines.
Precisely, so if all declarations are in the same place it does not take
much time or effort to locate that one place to wee whatever you need to
know.
This supports declarations for unused
variables to stay in the code regardless.
Yes it does, but it trades that off against accidentally re-declaring
variables and the time needed to verify that a variable has been
declared locally and so is not (accidentally or intentionally) a global
variable, or one form a containing scope.
In reality all three problems can be solved with something like JSlint,
which will inform you of declared and unused variables, re-declared
variables and references to undeclared global variables.
It is also easy then to forget that the declaration
is recommended, and end up with a property assignment
instead.
<snip>
A question that may be well illustrated with this method from dojo
(which has a line highlighted by me:-
dojo.toJson = function( _indentStr){
_indentStr = _indentStr || "";
var nextIndent = (prettyPrint ? _indentStr +
dojo.toJsonIndentStr : "");
var newLine = (prettyPrint ? "\n" : "");
var objtype = typeof(it);
if(objtype == "undefined"){
return "undefined";
}else if((objtype == "number")||(objtype == "boolean")){
return it + "";
}else if(it === null){
return "null";
}
if(objtype == "string"){ return dojo._escapeString(it); }
var recurse = arguments.callee;
var newObj;
if(typeof it.__json__ == "function"){
newObj = it.__json__();
if(it !== newObj){
return recurse(newObj, prettyPrint, nextIndent);
}
}
if(typeof it.json == "function"){
newObj = it.json();
if(it !== newObj){
return recurse(newObj, prettyPrint, nextIndent);
}
}
if(dojo.isArray(it)){
var res = [];
for(var i = 0; i < it.length; i++){
var val = recurse(it
, prettyPrint, nextIndent);
if(typeof(val) != "string"){
val = "undefined";
}
res.push(newLine + nextIndent + val);
}
return "[" + res.join(", ") + newLine + _indentStr + "]";
}
if(objtype == "function"){
return null;
}
var output = [];
for(var key in it){
var keyStr;
if(typeof(key) == "number"){
keyStr = '"' + key + '"';
}else if(typeof(key) == "string"){
keyStr = dojo._escapeString(key);
}else{
continue;
}
val = recurse(it[key], prettyPrint, nextIndent);
////////^^^
if(typeof(val) != "string"){
continue;
}
output.push(newLine + nextIndent + keyStr + ": " + val);
}
return "{" + output.join(", ") + newLine + _indentStr + "}";
}
The highlighted line is an assignment to an Identifier named - val -,
and I was wondering whether it was global or local so I went looking for
its declaration. If I had written the code its declaration would have
been at the top of the function body and I would have found it in a
couple of seconds (if that), but instead its declaration is one level of
indentation deeper than this assignment and it is in a branch of the
code that execution would not enter in the context of my interest in the
function's contents (the dojo.isArray function would have returned
false). The time wasted in shaving to scan every line of such a long
function for a variable declaration is not a contribution to easy
maintenance.
It is a commonly recommended 'best practice' that all variable
declarations and inner function declarations should be made at the start
of a function body. And it is a best practice that I agree with, because
it means you always know where to look for the declarations, the code
structure mirrors the handling of the declarations (that they are acted
upon before any other code is executed), and also the result does not
act to give the false impression, or re-enforce the false impression,
that javascript is block-scoped.
Richard.