See "About This JavaScript Site" in JavaScript Index and Introduction.
This is not a complete description; just salient points.
The proper standards are those of the World Wide Web Consortium and of the ECMA. The designs of MSIE before version 5.5 and Netscape before version 6.0 are only in part compliant; coding should be to W3C/ECMA, with special provision as required for earlier browsers.
Currently, the version which should be used for Web pages is Standard ECMA-262, "ECMAScript Language Specification", Edition 3 Final (March 2000). That has also been approved as ISO/IEC 16262. ZIP of PDF of ISO/IEC-16262:2002 - FoC.
The 4th Edition is (2007) in hand, may appear, and will be unsafe for general Web writing for several years after that.
Also, be sure that the HTML and CSS of your Web pages are valid - On Web Page Tools.
"ECMAScript 3rd Edition Compact Profile (June 2001)" is via ECMA-327.
Displays have different resolutions and colour depths. Browsers have different capabilities, and some subsets may not be enabled. Users have different visual abilities.
For informational pages, always accept what the reader is using; and check the behaviour of your work with different effective resolutions, by manually re-sizing your test window.
Design your pages to use no more advanced features than is reasonably necessary; where possible, include fall-back provision.
It is also necessary, of course, that the HTML be compatible - see my On Reading Web Pages - use HTML-testers, pay heed to access for the personally or technically disabled.
In JavaScript strings, "/" after "<" should be escaped with "\",
though most browsers do not enforce this. Write, for example,
document.write("<\/table>")
If JavaScript is not enclosed as "<--" ... "-->", then an HTML checker may get confused on seeing the JavaScript relational operator "<" followed by a letter; so put a space in between.
When choosing identifiers, avoid anything that might be or become in use in the system or the page (e.g. natural words); consider "bad spelling", such as 'skript'.
In some browsers, including Firefox, when document.write() opens a new page the previous include file contents are not available in that page; in others they are. So use, if possible, only one document.write.
In some Opera ("observed in versions 7.03, 8.54, and 9.01"), document.writeln() has no effect in PRE; use document.writeln("").
Example :-
<script type="text/javascript"><!-- /* The language attribute is deprecated The type attribute is now formally mandatory */ The script goes here //--></script> <noscript> In lieu of JavaScript here </noscript>
It is said that no browser now needs <!-- and //--> as above.
However, my program CHEKLINX, for testing local links on the (DOS/Win) master copy of a site, currently knows nothing of <script>, and, without those comment markers, it would not skip script. Therefore, I have been using them.
However, with them, W3's current (2003-11-01) TIDY complains more about script containing <N as in if (M<N) ... so I'll be looking into removing them and possibly changing CHEKLINX as needed. But M<N seems to need to be changed to M < N more generally.
In fact, the existing CHEKLINX is satisfactory on my pages without those HTML comment indicators.
See also in my Include Files for Include Files.
Many sites are legally, and many more are morally, obliged to be available to the handicapped, including the visually handicapped (UK : DDA, SENDA; US : ADA, S.508; IIRC). Such sites must be aware of the browsing facilities that are economically available to such users, and need to be coded to give satisfactory results with them. But such people will never contribute much to browser usage totals - disproportionately little, in fact, since they will be slow readers visiting fewer pages.
JavaScript for the Internet should as far as possible be browser-independent - as regards family and version, as regards location. On an Intranet, it may be that a specific browser or browsers, or locality, can safely be assumed.
When presented in public, code will be assumed to be for the Internet, unless explicitly stated otherwise.
Such settings may be read from the OS when the browser is started, when the page is opened, or when needed. It is not clear which is best, nor whether there is a standard. Browsers do differ here.
This section has moved into a new page Feature Detection.
Rewriting part of the body of a loaded page in a browser-independent manner is possible, but used to be tricky - see the Wryt test/demo in JavaScript Tests, and the FAQ of news:comp.lang.javascript. I now need only function Wryt.
Since scripts are downloaded for execution through links which may be slow, one should not include versatile but lengthy library-type routines if only a small fraction of the options are needed.
Eschew bloatware!
Repeat code as little as is practical.
document.forms["FormName"].item.state = condition ? "this" : "that" is better than if (condition) document.forms["FormName"].item.state = "this" else document.forms["FormName"].item.state = "that"
Where, in a section, different fields of the same Object are referred to, use a temporary for the common part :-
document.forms["FormName"].item.value = something document.forms["FormName"].item.focus() is better as T = document.forms["FormName"].item T.value = something T.focus() or as with (document.forms["FormName"].item ) { value = something focus() }
Where, in a page, a piece of code is substantially repeated, make it into a function with appropriate parameters :-
document.getElementById("X1").innerHTML = D1 // ... document.getElementById("X9").innerHTML = Q3 can be replaced by function Wryt(ID, St) { document.getElementById(ID).innerHTML = St } // ... Wryt("X1", D1) // ... Wryt("X9", Q3) which, if used repeatedly, saves space and increases readability. Also, it's then easy to replace Wryt with DynWrite of FAQ 4.15.
Where, in a page set, a piece of code is substantially repeated, convert it to a function and move it into an included file.
This page, like others of mine, has access to functions declared in file include1.js (invoked in the <HEAD> section of this page) and visible in page Include Files.
Field Validation is often coded repetitively; but see in js-valid.
Consider these, tested in JavaScript/HTML/VBS Quick Trials :-
function Reed(f, s) { return document.forms[f].elements[s].value } function Rite(f, s, Q) { return document.forms[f].elements[s].value = Q } Reed("F", "Vbs") Rite("F", "X3", "Answer")
Identifiers are case-sensitive, generally start with a letter, and cannot start with a decimal digit.
Programmer-introduced identifiers should not be correctly-spelt (or US-spelt) words used in computing, to reduce the risk of any clash or confusion with system identifiers and other words.
Every identifier used within a function should either be declared as a var within that function or be passed in as an argument (except when it is necessary not to do so). The scope of such an identifier is that call of that function.
Identifiers that need to be global within a page should normally be declared, outside any function, with var. (When I wish to display the declaration, as is common in these pages, they need to be in functions, so var cannot then be used.)
The character $ is allowed in identifiers; it is supposed to be reserved for machine-generated code. A function $ can be used as an abbreviation for something else commonly used, such as document.getElementById.
The traditional British Army recommendation for instructors (which I would like to have authoritative wording for) is allegedly : "first you tell them what you are going to tell them; then you tell them; then you tell them what you've told them". Likewise, a scientific paper needs Introduction, Details, Conclusion. I'd equally suggest no fewer than three passes on reading a non-trivial subroutine. The first pass would show the overall structure; the second would check detail, and the third would review what was done and what was not done.
Function eval() should be used only when it is necessary to evaluate a string which either is supplied, or must be composed, at run-time; the string can be anything from a simple (but unpredictable) expression such as 12*2.54 to a substantial (but unpredictable) piece of JavaScript code.
Function eval() should not be used as a crutch in addressing JavaScript entities. See the FAQ of news:comp.lang.javascript and then JavaScript Square Bracket Notation by Richard Cornford. But it seems simpler, usually, just to use dotted fields in the address.
Function eval() should not be used merely to evaluate a pre-coded expression; in that context it is superfluous.
It can be useful for transforming a string into an expression, for example when calculating a checksum.
It can be useful for allowing the input of an arithmetic expression, where a number is needed.
For appropriate use of eval() see in my JavaScript Demos & JavaScript/HTML/VBS Quick Trials; and Astronomy / Astronautics 3, Gravity 2, Annual Holiday Dates, JavaScript Include Files.
As alternatives,
new Function("return "+str)() function EVAL(str) { return new Function("return "+str)() }
Difference : the evaluation of eval() happens in the current scope.
For a function named St = "Fn", a reference to the function can be obtained by eval(St) but window[St] is preferred.
Every switch statement should have a default: at the end,
unless it is absolutely certain that all possible cases are covered, and
will remain covered, above. If it is intended that all cases be covered
above, use
default: alert('Blunder')
or suchlike.
A switch statement can be used instead of a nested if ... else structure, and may be more readable :-
var X = 25 // the variable switch(true) { case X<10 : alert('<10') ; break case X<20 : alert('<20') ; break case X<30 : alert('<30') ; break default : alert('big') }
If the case expressions are, or can readily be transformed into, a sequence of integers, and the selected statements are similar, then it may well be advantageous to change to selection by array indexing.
X = B is far better than if (B) { X=true } else { X=false } X = !B is far better than if (B) { X=false } else { X=true } if (B) is far better than if (B==true) if (!B) is far better than if (B==false) X = [Y,Z][B] beats if (B) X=Y ; else X=Z for complex X
What simple, general rules for execution efficiency are there?
Avoid repeated sub-expression evaluation.
Join strings with care :-
R += "aaaaa" ; |
R += "aaaaa" + |
With R already large, how do these compare? Tests indicated that the second was somewhat faster in MSIE 4. | ||
var R = [ " here is part 1", " here is part 2", " here is part 3", ... "" ].join("") ; |
But Array.join() is reportedly much faster. |
Preincrement should be faster than postincrement; likewise decrement.
I have read that the second should be considerably faster than the more obvious first :-
for ( i = 0 ; i < allFields.length ; i++ ) { ... for ( i = allFields.length ; i-- ; ) { ... i = allFields.length ; while (i--) { ...
Code should not be unnecessarily bulky, since that increases download time. Remember some users have slow and/or costly links to the Net. Indent lightly, or strip it before uploading. Avoid trailing whitespace.
Balance considerations of download time and execution speed, bearing in mind frequency of execution.
Tip : To determine the length of a function F, use F.toString().length.
Use *.js files to save repeating code within a page set - see the Wryt test/demo in JavaScript Tests, the viewing links in Index & Introduction, the source of this page, and the general material in Include Files.
Always declare each variable with var, unless certain that it's not appropriate to do so.
Program for the least advanced browser that you can manage with, to maximise your audience.
Moved to JavaScript Debugging.
Trying to configure for varying local preferences is often a mistake. Browsers are not always correctly configured for their actual users. Where practicable, it is better to use a single internationally-understandable format.
Internationalisation is greatly preferable to Multinationalisation.
See Brian Forté : International Writing; and my Decimal and Thousands Separators.
Multinationalisation involves configuring the display, or the allowable input, differently for different localities, for example showing a date as 23/04/00 in the UK and 04/23/00 in the USA.
"Locale", as in toLocaleString(), is an important term, though one that I don't know enough about. That Method, I read, can apply to more Objects than the little book which I have implies. Locale-dependence can be browser-dependent.
In writing HTML or JavaScript (or Java), remember to allow for locale-dependent conventions.
Decimal separators are an obvious case, "." & "," at least.
Numeric date field order varies, so follow ISO 8601 and use YYYY and either a word for the Month or the order YYYY-MM-DD. "UTC" and "GMT" may be alternatives to parse; unexpected Time Zones may be present; both Australia and America have an EST, and BST has at least three meanings. Where possibly significant, state the Time Offset unambiguously, or use "local".
Customary usages and field names vary for, inter alia :- date layout, week numbering, decimal and thousands separators, list separator, currency notation, local time, time layout, 12/24-hr clock, local taxes, addresses, post codes, telephone numbers, summer time dates, given/family name order, ...
Internationalisation means configuring a single display format, or using a general form of input, which will be acceptable world-wide, often in accordance with ISO standards; 23rd April, '06 becomes 2006-04-23, which all can understand without ambiguity (No-one uses 2006-23-04, though 2006 23 Apr is possible [and 20062304, alas]).
Beware - international standards are often unknown, forgotten, or just disregarded. It seems that the average European mainlander may assume that everybody complies with international standards, and the average American totally disregards international standards.
International standards are not always obvious.
I was once assured, for instance, that one should allow 28 digits
worst case for storing telephone numbers (as the message is old, I've
removed the name) :-
From: *@etlxdmx.ericsson.se
Date: Sun, 3 Jul 94 12:55:35 BST
Currently the maximum number of digits in a called
subscriber's number is 28, actually dialling 28 digits is very hard
to do but never the less 28 digits is the requirement requested by
all phone administrations.
But I've since read "A telephone number is a string of up to 32
characters which complies with ITU recommendation E.123.".
And I'm told that BT (UK) say 10 to 18 digits, which include the
leading zero.
A short overview of E.123 : Notation for Telephone Numbers.
Remember also that words or phrases such as "elevator", "gas", "pavement", "first floor", "public school", "the government", etc., have different meanings in different countries; where necessary, ensure that ambiguity is resolved, by context or otherwise.
In the American language, the term "English Language" has quite a different meaning to that which I myself am used to.
To indicate a currency, only the standard TLA is reliable : GBP, USD, FIM, EUR, ... . The symbol "$" is ambiguous, and others may not be available in all browsers - see Europe and Euro.
Be aware that very specific rules apply to conversions of currencies locked to the Euro.
No code can handle all cases correctly, since it is a matter of whim. The only safe change that may be socially acceptable is to force to upper case. Remember that some cultures put the family name first, or do not use one, or otherwise differ from the Anglo-Saxon norm.
Remember that Earl is a forename in the USA, but a title in the UK; I've even seen a Web page referring to "Alfred Lord Tennyson"[*].
There is often a wish to import and perhaps insert in the page at run-time from a plain text file, which cannot be done directly.
One can, however, put the text as a string or an array of strings, assigned to a variable, in an included *.js >file; it is then available, by name, within the importing page. This may require very little editing of the text. In a DOS-compatible system, tools such as those in my MS-DOS Batch Programs can be used for the editing.
To insert material on the current page, see Rewriting Within A Page herein.
The ".Sign." column in the Table on the right displays what your browser shows, in the current Table font, for the Unicode entities in the "Value" column. The following columns refer to Times New Roman font on my systems.
JavaScript uses \xHH \uHHHH, where H is Hex. HTML uses &#N; where N is a decimal number; and, in preference, named entities such as π.
References :-
JavaScript and HTML are repeatedly both downloaded and interpreted. Therefore, excessive white space should be deprecated. However, they are intended also to be readable languages, so a little white space should often be used.
If the code itself may be handled by any tools designed for plain text - such as Notepad, printers, Usenet News, text editors and viewers, etc., it will be better to keep the line-length under 80 characters (72 or under for News).
Code generated by dedicated WYSIWYG editor programs is often highly redundant; it would be courteous to prune it by hand or otherwise, especially for high-usage pages.
Consistent use of a modicum of white space makes code more readable and maintainable.
Code should be indented to show the logical structure; I usually use a unit of two spaces (tab us too big, especially in Usenet), and indent for each level of statement structure and for continuation lines within statements. The "Indt" button in my JavaScript/HTML/VBS Quick Trials can indent for levels, and some continuations, automatically. At first glance, this code indenter looks much better.
I find it more readable to have white space immediately following "//"; a single space is enough. This is particularly beneficial if the material may be at any time be put in News (or Mail), since MS OE adds prefixes to "//<letter>".
It's helpful to have at least one space, generally, before a statement which directly follows a semicolon; it's often useful to have one after a comma, ones around assignment and concatenation signs, and to put some in bracketed maths. It's helpful to have it on each outer side of the parentheses associated with if while for function switch with.
JavaScript as written does not require a visible terminator for every statement. It needs some form of separation between statements. A "free" semicolon is a separator. A newline may be deemed to imply a semicolon. Then every statement not otherwise visibly terminated will be terminated by a semicolon.
When the parser meets a semicolon (except in for(;;), strings, comment, &?), the current statement must be complete.
Comment starting // extends up to the end of the line, but does not include the newline; comment using /* ... */, if containing any newlines, counts as a newline.
In at least some browsers, newline can be escaped with \ - it's not a proper thing to do (it is not in the ECMA spec), but it's nice to understand it if it is seen.
When the parser sees a newline, the statement will often continue; otherwise the newline will behave as a statement separator. In particular, a semicolon will be implied if return ends a line.
Some authors like to end a line with a semicolon wherever possible; but that is not necessary. If in doubt, however, insert one, or omit the newline.
But, for example, the inappropriate addition of a semicolon after for(;;) but before the intended loop code is an error which may be difficult to spot.
For a more detailed specification of parser action, see ECMA-262 or an equivalent reference.
Comments? Is this section Mac-compatible?
Source code, being creative material, is automatically copyrighted, affording legal protection. The better site administrators will act against known copyright breaches by their users.
For display of source in my pages, see Code Display on This Site.
The actual source of a function can be obtained, anywhere that it is known, by function.toString() and can be displayed; I do this in boxes with coloured borders in these pages. Non-function code can also be shown, where it is executed.
It is not possible to completely protect the source code of a Web page from being viewed. Web pages are fetched with the HTTP protocol, and so can be fetched manually, as plain text, by using Telnet.
It is possible to encrypt or obfuscate Web source material. But if it is intended to be Web-viewable by any normal browser, the code needed to show it must be downloadable.
It is possible, with script, to disable or redefine right-click; and this will hide code from those who only know the right-click way to access it and are running script.
It is possible to put the heart of the page in a *.js file, in which case it will not be shown by a simple View Source.
However, disabling right-click might be wanted for reasons other than concealing code; see below.
Methods, some browser-dependent, for viewing Web page source include :-
The later ones allow viewing of include files, such as include1.js which is used by this page.
Some authors will want to encourage source viewing of HTML or script files. Author-provided links, maybe browser- and setup- dependent, can be such as :-
When JavaScript writes a new page, it uses Unicode. If plain text is saved to disc, it can be converted to "ASCII" with DE-UCODE.BAT (needs MiniTrue) via index.
Deprecated, for accessibility reasons; consider the Accessibility Acts (DDA, SENDA; ADA, S.508).
I read that <body oncontextmenu="return false"> will do it in MSIE; I did not get it to work in MSIE 4.
Probably impossible in a traditional Mac.
I have read, with regard to Web pages, that: Neither Java nor JavaScript in a default security environment has any access to the local file system.
Input should where feasible be validated at the client, for faster response. Input should always be validated at the server, since the client may readily be suborned.
If used to represent E-mail addresses in Web pages, that encoding may reduce address harvesting and resultant spam.
For protection against being watched, use the Password object for input.
Code such as
has two defects : the password, "Sekret", is revealed by View Source (etc.), and so is the hidden URL.
To protect the password, put it through a one-way function; the following should do (provided that Math.tan() gives exactly the same on all systems, which I believe it should - but tests show that not to be the case) :-
Here it is impractical to deduce the password even if the encoded form is known. Chaos theoreticians can probably suggest more efficient functions.
The returned string can then be used directly as part of the URL :-
The author chooses the password, and from it determines the URL needed; have no other pages there with names starting 'X'.
Note that the "hidden" URL will be discoverable once the correct password is used.
Do not, however, rely on this suggestion without proper verification.
[*] which should, of course, be "Alfred, Lord Tennyson".