Javascript related notes
From Helpful
| For more webdev-related articles, see the webdev category. Among the more interesting are general webdev notes, Javascript related notes, CSS notes, browser peculiarities, jQuery |
ECMAscript, Javascript, JScript
ECMA-262 is implemented by JavaScript and by JScript. The different names are quote-unquote necessary because both names are trademarked. Calling it ECMAscript may be more practical, also since there is very little relation to Java, and any implementation should be comply with ECMA-262 specs. Note there are also non-ECMA features (only a few, though), which you should know about to avoid writing code that will cause errors in some places.
Note that ActionScript is also an ECMAScript implementation, (one with non-portable extensions).
In browser scripting, you are dealing with both the scripting language and the DOM, these days primarily the W3 DOM (verify), though some DOM operations may be buggy in some browsers, IE or otherwise. MSIE seems to add the largest chunk of non-standard-DOM functionality. Again, avoid it if you want cross-browser functionality.
Technically, the exact meaning of your code may be a little volatile between browsers and between major versions (variations as in 'half-a-decade-old'). Note that if you do anything FancyWeb2.0 that people want to come to and see, the people interested in this shiny are often easily be convinced to upgrade their browser to the latest version, if they haven't already, so do not torture yourself with "Has to be compatible with ten year old browsers" usability guidelines. Of course, you should take "has to work in all current browsers" seriously.
Differences
| This article/section is a stub — probably a pile of half-sorted notes and assertions some of which may well be wrong, and not verified as a whole. Feel free to add or refine. |
(Note: this is somewhat outdated, referring to articles from ~2006 and earlier)
See, for example
- "JScript Deviations from ES3" (which reports IE, FF, Opera and Safari)
- http://www-128.ibm.com/developerworks/web/library/wa-ie2mozgd/ (IE/mozilla compatibility notes)
Some of the interesting ones:
Syntax
| This article/section is a stub — probably a pile of half-sorted notes and assertions some of which may well be wrong, and not verified as a whole. Feel free to add or refine. |
Firefox accepts:
{ 'b':'c', }
IE does not; it expects the comma to mean a new item comes next.
Firefox supports indexing of strings for characters, IE does not. (Use String.charAt())
DOM
| This article/section is a stub — probably a pile of half-sorted notes and assertions some of which may well be wrong, and not verified as a whole. Feel free to add or refine. |
JavaScript access before loading is finished:
- IE may trigger "Operation aborted" error and show / reload to "page not found". It gets confused about altering the DOM (e.g. appends) while it has not yet finished parsing it (though the actual cause seems a bit more specific) [1]
- Firefox seems to not cause error, but may obviously not do what you meant.
Non-standard (often IE hacks) features include:
- document.all
- document.images
- document.frames
Events
| This article/section is a stub — probably a pile of half-sorted notes and assertions some of which may well be wrong, and not verified as a whole. Feel free to add or refine. |
Loose Javascript/DOM reference
Also see:
- Some useful cheat sheets
- Gecko DOM reference: TOC, index
- Developer.mozilla.org references (generally)
- http://developer.mozilla.org/en/docs/Gecko_DOM_Reference including things like:
- http://msdn.microsoft.com/en-us/library/ms764730.aspx ('HTML and DHTML Reference')
- http://msdn.microsoft.com/en-us/library/ms533055(VS.85).aspx ('DHTML properties')
Interesting...
Objects
- window (or, in tabbed browsers, tab)
- document (when using (i)frames, there is more than one of these about. Create DOM elements from the document you want to add them to)
- document.frames is an array that contains the (direct) child windows(verify).
- forms[], anchors[], links[], applets[], embeds[], stylesheets[], plugins[] (often not necessary)
- location, referrer, title, cookie, domain
- getElementById, getElementsByName(), getElementsByTagName()
- createElement(), createTextNode(), createAttribute() (see related nodes' functions, like append())
- (more related)
- bgColor, fgColor, body (verify)
- location (applies to document and window. Note: not standardized, and I'm not sure about the variation)
- href (changing this surfs away. Assigning to location (and not its .href attribute) is sometimes hacked to work/depended on too(verify))
- Also its parts: (examples for http://example.com:80/index.html?a=b#q)
- protocol (e.g. http:)
- host (e.g. example.com:80 or equal to hostname if no port mentioned in url)
- hostname (e.g. example.com)
- port (e.g. 80, but this is an empty string unless the port is mentioned explicitly in the URL)
- pathname (e.g. index.html)
- search (e.g. ?a=b)
- hash (e.g. #q)
- replace, assign, reload (all non-standard?(verify))
TODO: (verify) all the frame/window stuff
Top-level/global/Object functions
Timers:
- timerID=setTimeout(func_or_codeAsString, mstime) [2], clearTimeout(timerID) [3]
- timerID=setInterval(func,delay) [4], clearInterval(timerID) [5] (triggers every delay ms until you clear it)
When you pass in a function reference (instead of using string code), FF allows you to pass in parameters, but IE does not support this.
Because of this, the string way is more compatible way to pass in data, though you'll often have to escape your values to do so cleanly.
- parseFloat(s), parseInt(s[,radix]) (without radix, zero padding may lead to octal interpretation)
- toString() (Number.toString() seems to have radix)
- escape(), unescape() (URL encoding)
- eval()
Utility classes / Class methods
Mostly core Javascript/JScript/ECMAscript. Note that the below mixes class functions and instance functions. Sometimes there are comparable alternatives.
- Math (utility class)
- abs(), cos(), ceil(), min(), sqrt(), exp(), etc. (fairly obvious, all take floats)
- E, LN2, LN10, LOG2E, LOG10E, PI, SQRT2, SQRT1_2
- random() (generates values 0.0≤v<1.0)
- Function
- String
- match(re), replace(re,s), search(re), split(re) (no strip(), but is fairly simple, see here)
- charAt(i), indexOf(s[,i]), substr(i,len), substring(i,i) note the difference between the last two
- length
- Array
- length
- push(o), pop(), shift(), unshift()
- concat(a)
- slice(i[,i]), splice(i,i[,a]),
- join(str),
- sort([f]), reverse()
- Number (note that NaN is an object; typeof(NaN)=="number")
- toString(), toPrecision(i), toExponential(i), and a few constants
- Boolean (...whatever)
- Date (mostly object setters/getters, some conversion and some system time gets. see e.g. [6])
(s refers to string, re to regexp/string, o to object, a to array, f to function, i to integer (often an index), len to an integer length)
Regular expressions
In javascript, these can be constructed with syntax. They can also come from instantiating the RegExp class, which is useful when you want to compile a regexp stored in a string. The following are roughly equivalent:
/[a-z]/g RegExp(/[a-z]/g) RegExp("/[a-z]/g") //And yes, that means the following is valid syntax, even if it looks a bit weird. /[a-z]/g.test('Yay')
These are Unicode-capable.
For now, see things like:
- http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:RegExp
- http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Guide:Regular_Expressions
- http://www.javascriptkit.com/jsref/regexp.shtml for now
TODO: finish.
Useful scoped things
As in, usable in a function and not global.
- parent (refers to script's containing document(verify))
Node...
Variables/constants
- id
- nodeName, localName, nodeType, nodeValue
- innerHTML (not standardized, but widely implemented for convenience)
Functions
(generally on all nodes)
- nextSibling, previousSibling, parent, childNodes[]
- getAttribute(str), setAttribute(str,val), removeAttribute(str)
- appendChild(), removeChild()
- addEventListener(), removeEventListener()
Events
- onblur, onfocus
- onclick, ondblclick, onmousedown, onmouseup, onmousemove, onmouseover, onmouseout
- onkeypress, onkeydown, onkeyup
- onresize
Some nodes have more, where sensible.
More on events
Common quirks
There are a good number of details, though.
In practice, it pays to use one of the javascript libraries, which evolve to be more cross-browser than ten-minute few-liner code will be.
Some of the quirkyness you may want to know about:
- Browsers may have their own events. Particularly IE has a bucketload of IE-only onsomethings (e.g. for dragging). Avoid them if you want compatibility.
- Even the events common to all browsers may have somewhat different semantics between browsers. For example, onchange behaviour varies a little, I'm guessing because of vague wording in the standard.
- The structural difference between IE's model and the W3C one - see e.g. http://www.quirksmode.org/blog/archives/2005/08/addevent_consid.html
- IE's model apparently only captures, and doesn't bubble (capturing and bubblig refers to when, in propagation, an event is handled) There may or may not be a way around this(verify).
Each event handler has an event object handed to it as a parameter. It has some potentially useful members and functions; see a cheatsheet for details.
However, IE does not hand along events in event handers. They instead are in the global window.event (which works fine since JavaScript isn't threaded).
See also:
- http://www.quirksmode.org/dom/w3c_events.html Quirksmode (in)compatibility guide
- http://www.quirksmode.org/js/events_compinfo.html quirksmode
- http://developer.apple.com/internet/webcontent/eventmodels.html
- ...various other pages
Common events
Also read quirksmode on the matter.
Mouse
onmouseover mouse enters element's area onmouseout mouse leaves area onmousemove Moves the mouse pointer within an element. onmousedown mouse button is pushed down onmouseup mouse button is released onclick push-release both in the same element ondblclick double-click within system doubleclick time
Notes:
- If the element is near the edge, the element may stay in focus even though the window has lost focus; the OS' window focus the document elements' focus are diffent realms. This applies to mouseover and focus/blur.
- onmousemove is triggered every pixel of movement; don't put heavy work in this.
- There are four different pairs of x/y attributes in the event, but most/all are useless.
- you can get the relevant button from which and button.
- the values are different between browsers
- Not all browsers and OSes support this on onclick, which may only fire for left clicks(verify)
- the non-standard ondblclick also seems implies absence of two onclick events? (verify)
- mouse reaction areas seem to correlates with the CSS background styling. If something is its default transparent, it may not react at all. Give it a color to make sure it's not quicky about this. IE's logic seems quickier; I have yet to figure out the details.
Keyboard
onkeypress key is pressed AND released. onkeydown key is pressed onkeyup key is released
Notes:
- Note that this, mixed with OS messaging, may make it technically possible to e.g. catch a keydown but not a keyup for the same key.
- onkeydown and/or onkeypress may or may not fire repeatedly based on the browser and OS.
- The pressed key will be in e.which in compliant browsers, and in window.event.keyCode in IE. It seems some browsers also added keyCode.
(TODO: see [7], and see how many are IE-only)
Others
onfocus input element gains focus
onblur focus is lost. Seems to have priority over e.g. a click
that probably caused this.
Event propagation
- Events propagate two ways (basically a treewalk), first by being captured down the tree (root first, on its way to the target), then bubbling up it from the target to the root element. Note that W3's terms argue more from the perspecive of the node itself, and from an ongoing process of treewalking.
- If something captures, it will be called before getting to an object.
- There are default actions for some events to allow the browser to do sensical things like selecting text. These are independant of your own functions and always fire unless you call an event's preventDefault()before it bubbles back up to them.
- return falseis mentioned vaguely as both a further-bubble preventer and a default-preventer - it seems to do both by canceling all further event handling for the event (verify) (used e.g. to cancel form submit by value-verifying function). It is apparently a nasty way of controlling behaviour, with browser-dependant behaviour, so avoid it when you can:
- Events can be cancelable (like clicks) some are not (like losing focus) which means you can or can't cancel all further propagation for and from within some event.
- 'window.event.returnValue=null' seems to be the IE equivalent of either 'return false' or precentDefault() (verify)
- See sections below about controlling propagation
Controlling propagation
Events happen to things in trees, like explained. Sometimes it is convenient to allow events to do potentially do something at all nodes it passes, sometimes you want to prevent that.
You can usually argue this per action type. When you want things to follow your mouse, you want mousemoves to not be blocked when another element happens to capture it, whereas when you click a button, you probably don't want something under it to also react to the click.
When you want to prevent caputing and/or bubbling, you need to do so explicitly. See e.g. this.
return false
Some people suggest return false as the last part of the event handler function.
Since the onclick handler is generally executed first (always?(verify)) and the href handling is apparently part of the same event handling (likely not standardized) you can return false to stop the a href.
Upside:
- Sometimes a simple way to avoid another handler from being used
Downsides
- is an ugly nonstandard hack that does not behave consistently between browsers, so you can't really count on this.
- ...that aborts all handling of the current event, which breaks complex interfaces that rely on independent handlers
onSomethings' default actions
when you want to drag and drop things, you can do so with basic events such as onmousedown, onmouseover, and so on. However, without some alterations, onmousedown will both do what you tell it to do and what it would normally do. For example, if you want to drag-and-drop a div, you don't want it selecting the text inside it complain (in a mouse cursor way) you can't drag an image. You can avoid this default functionality by in the/a event function canceling the default action, perhaps:
var dragstart; anElement.onmousedown=function(e) { dragstart=this; //maybe some visual feedback if (e && e.preventDefault) e.preventDefault(); //prevents weird drag side effects }
I believe this is DOM2(verify), hence the object detection. In practive you may well have to also prevent bubbling and/or propagation to avoid the default action of one of the under/overlying elements.
Attaching event handlers
Background
Common methods:
- Setting onsomething="code" inside HTML is not a DOM standard, but which you can assume all widely used browsers will support. Note they usually put these events in the bubbling phase.
- setting domreference.onsomething=functionref; from a script are also not standard, but also generally supported. Note: You should use all-lowercap names for most-browser compatibility.
- The DOM standard says to use addEventListener (see e.g. [8]), but IE doesn't support this (it defines its own method instead).
There is more ways, but the most compatible way (that is also short; in a library you could also solve problems like IE's rule of one handler) seems to be the DOMelement.onsomething = function way, or assign a function reference indirectly. You'll probably want to use closures to pass in arguments.
Note, however, that assigning a function this way will replace any if it were previously set. This combines with IE's problem of allowing only one event per event type per DOM element whatever way you choose.
You can work around by e.g. making actual handler one that keeps a list of functions to call, and does so. It's easier to use some library to do this for you.
Notes on HTML-inline script code (void(0), "#", etc.)
| This article/section is a stub — probably a pile of half-sorted notes and assertions some of which may well be wrong, and not verified as a whole. Feel free to add or refine. |
techniques / workarounds
javascript:void()
<a href="javascript:void(window.open('http://google.com'))" >
<a href="javascript:void(a=1);void(a+=2)" >
Putting void(0) in <a href renders the link useless in a location-altering hyperlink way: void()'s function is to wrap around code, swallow any return values, and always return undefined.
void() requires a parameter (officially; some implementations won't trip over its omission), and 0 is common because it is a short, ignorable value.
void() can only contain expressions, not assignments and such. You can work around this by calling a previously defined function, or defining and immediately calling an anonymous function (verbose, but works and is valid javascript):
void(function(){var a=10;}())
# in href
Using a hash (as in a#) in href will
- not reload the page
- scroll (skip, really) a page to a particular section
- ...to a named anchor, defined like <a name="helpsection">) if it exists
- ...or the top of the page if it does not
Upside:
- will work in any browser,
- doesn't do anything strange or different when javascript is disabled
Downside:
- In most cases, will move the page
There is a semi-workaround that makes this a simple option to have onclick in javascript browsers, and degrade to the href in those without.
Alternatives
Many solutions try to work on <lt;a> tags so that the link will automatically be styled like others in the page.
This is often not necessary, as javascript-supporting browsers by and large allow handlers on any objects. However, it is often harder to explain to users that random bits and bobs are in fact clickalbe things.
code in href
<a href="javascript:code">
One way of adding javascript to a link is to add it to its href attribute with a 'execute the code when you click the link' intent. This isn't only works because of convention, but it's a pretty wide convention.
Upside:
- Simple
- valid (X)HTML in and of itself
Downside:
- Is a non-standard way of adding handlers to (X)HTML (most browsers support it, though)
- No graceful degradation - no javascript means no link at all
- middle-click won't load link in new tab
To worry about:
- if the code('s last constituent) returns a string, object or such, the browser will assume that was an URL and will navigate to it. Workaround: using void() or similar
void in href, code in onclick
<a href="javascript:void(0)" onclick="code" >
Upside:
- Simple
Downside:
- Only works in javascript-aware browsers, that do not have javascript disabled.
- IE does not always like this solution.
Note that it is neater (in HTML elegance and in browser compatibility) to register the onclick handler via code instead.
code in onclick, omitting href in <a>
You can omit the href attribute. DTDs (HTML4, XHTML) list it as #IMPLIED, meaning omission is technically valid (recall that anchors are a tags with only a name)
Be aware of varying browser behaviour, of link semantics interaction with <base>, and note that some (stupid) scripting may assume href's presence.
If you are going this way, I'd almost say that you might as well use a span, add an onclick, and style it the same as you style regular links in your app.
Gracefully degrading
If you care about degrading for JS-disabled browsers and search engines, you'll probably want to
- write plain HTML that will work if no scripting would follow
- use an onload script to alter the href and/or add events to have it behave with the popup windows/ajax/redirects you wish.
- (This can include adding mouseover/out handlers that set window.status, so that the status bar still displays the link even if you set href to # or void)
Possibly:
- Use a trick that behaves somethign like href="realpage.html" onclick="window_or_ajax_load('realpage.html');return false" (see notes on return false, though)
Semi-sorted notes
(relative) basics
Optional function parameters
All are, actually, JS fills in undefined for any ommitted ones. It's just that most code will trip over that when you're not counting on it. You would write something along the lines of:
function upper(s,alsoStrip) { var r=s.toUpperCase(); if (alsoStrip!==undefined) {r=r.strip();} return r; }
(...assuming you have added a strip() function to the String prototype.)
In this particular case you don't have to do identity test - you can just write it as simple as if (alsoStrip) ... so that undefined, null, false and 0 are all coerced to false.
In other cases you may specifically want to have 0 be a value you can pass in, in which case you would check against undefined as it will be the 'unspecified' value.
this
'this' is bond to different things in different context, which seem a little magic at first. Particularly:
- In object members, they are the object
- When used as event handlers, they are the DOM element they are set on
- ...more?
Classes
(note: these are one-liners to be able to quickly paste and test them in e.g. firebug)
To create objects (with this.-style functions, rather than a more C-like handle-this-struct) you apparently need at the very least a parameterless constructor, such as:
function Node() { }
At this point you can e.g. say They act as classes because you use them that way. If you also want a real constructor you can add that too:
function Node(id,str) { this.id=id; this.str=str; }
The effect is simply that the returned object now has some things set on it. The class will be the same name as the constructor, and you can add prototype functions that you can call on objects of this type:
Node.prototype.getId = function() { return this.id }
Node.prototype.getStr = function() { return this.str }
This also uses the object values we set in the nonempty constructor. Now we have a usable object:
var n = new Node(1,'fish'); alert(n.getId()+' '+n.getStr());
Note: you can get an imitation of classes by defining function inside the constructor. The downside to this is that you are using closures, and since javascript doesn't seem to support nested closures, that limits you from using closures in the class code.
Object types
typeof(something):
- Things you tend to use as if they are simple values report as themselves:
- "number" "string" "boolean" "function", and "undefined"
- Things like Array, Date, Math, RegExp and Error and null are considered:
- "object"
You can use this e.g. to make libraries more flexible, by alowing them to take both a DOM element reference and a document ID.
Array ≈ stack ≈ queue
Given that:
- push() is 'add to end'
- pop() is 'take from end'
- shift() is 'take from start'
- unshift() is 'add to start'
...you can use an array as a stack using push() and pop()
...and as a queue using push() and shift() (or pop() and unshift())
They're probably not the fastest possible implementations of said data structures, but they can be convenient.
DOM clarifications
- documentrefers to the document somewhat abstractly,document.documentElementmore specifically to its root element, <html> in HTML docs. The documentElement is not guaranteed to provide things like getElementById, though it often does (you should use document for these)(verify). However, this seems to be a mess: there are browser-specific details, see [9] and [10].
- Nodes versus Elements: Nodes are the DOM tree building block, so pretty much about everything addressable (including attributes, text inside elements, and elements) inherit from a Node. What you're probably used to thinking of as HTML's units, <tags>s, are Elements. Many DOM-related functions handle Elements. The main exceptions are the functions to do with creating/removing/changing child nodes. The terms are a occasionally abused, though.
- document.getElementById('val')looks for a single elements with the givenidattribute value
- document.getElementsByName('val')looks for all elemens with the givennameattribute value (DOM2)
- document.getElementsByTagName('pre')looks for all elements of a particular tag type
If you want a document.getElementByClassName, you'll have to implement it yourself. There are various ways; DOM3 allows it a clean way, but a more compatible version involves walking all nodes that getElementsByTagName('*') returns and testing each 'class' attribute value for the class (not a string equalty because of the multiple-class possibility). See e.g. this. See the next section for one implementation.
Keeping code out of your markup
When you can move code ouside your (HTML) markup to the <head> section, you generally make the page more maintainable.
This generally means you need that javascript to go through elements and doing something to the DOM, like changing style, adding nodes or adding event handlers. For example, the following code indirectly swaps visibility via a CSS class:
var divEl = document.documentElement.getElementsByTagName("div"); for(var i in divEl) { var el = divEl[i]; //do stuff with it. }
Various modern JS libraries (jQuery, Prototype, that lot) tend to make this rather simpler.
Note, however, that it may be clever to put <script> sections after your head.
Also, when there is substantial code in your page that is static, you should think about putting it in a separate file (or rather one or just a few files for your project; fewer .js files means less loading slowness through lag.
Interesting details and a few gotchas
Easy regexp/substring test
//given the following string: var s = 'foo'; /o/.test(s) // ...is easier to type than... s.search('o')!=-1
(DOM) Objects as (hash)maps
It's regularly noted that any object is a hash map. Yes and no. It does act like a map, but I wonder if there is a real hashmap behind it.
More pragmatically: you basically should never assume that something that isn't a {} or a new new Object() can be used as a map, because everything from Object-derived classes (such as Array) to DOM elements and prototypes has other members, and it's all in the same namespace (though it seems builtins are not(verify)) so may interact in nasty ways and accidentally break something when you hit a name that something else used, particularly when you use DOM objects.
Another caveat about storage this way is that keys are always strings. If you try to store anything else in the key, it effectively will be toString()'d(verify), which may or may not disturb you if you mix only numbers and strings, but may be nasty to you when you handle objects.
Create a new object:
var o=new Object();
o['b']=5; //arbitrary strings
o.a='3'; //this style access the same, but requires syntactical validity
o[1]=2; //implies "1"
delete(o[1]);
for (var i in o) alert(''+i+': '+o[i])
You can test for presence/absence by doing an identity comparison against undefined, e.g.:
var val=o[4];
if (val===undefined) alert('not there')
...except that you can also store undefined as a value; I'm not sure how to distingish, though in many cases you won't need to store undefined, especially when you also have null, and null!==undefined But! - null==undefined, so it is probably worth it to implement a few simple wrapper functions around this to avoid accidentally using == instead of ===.
Note: There is also a hasOwnProperty(s)
There is a minimal STL-like library (no algorithms, mostly just the basic collections), see [11].
for and objects
For will iterate over object members, even if the object is an array. This means any additional members (such as prototype functions added by libraries) will mess up iteration written with a foreach in mind, such as:
for (var e in arr) {
Instead, you want
for (var i=0; i<arr.length; i++) {
This pops up in different forms. element.childNodes is actually an associative array that just happens to have nice index-based keys, so:
for (i in element.childNodes) alert(element.childNodes[i]);
...prints nodes and two non-element members: item and length. Instead, you should use:
for (i=0;i<element.childNodes.length;i++) alert(element.childNodes[i]);
String replace replaces only first case
A string-string replace will only replace the first match:
'aa'.replace('a','b') == 'ba'
You can make that global with a syntax-sugared regexp:
'aa'.replace(/a/g,'b') == 'bb'
When the thing to be replaced comes from a variable you'll have to compile it into a regexp more explicitly:
var pattern='a'; 'aa'.replace(new RegExp(pattern,'g'), 'b') == 'bb'
Page reload/navigate
| This article/section is a stub — probably a pile of half-sorted notes and assertions some of which may well be wrong, and not verified as a whole. Feel free to add or refine. |
I never know which to use. Are any of these incompatible?(verify)
It seems window is effectively interchangeable with document -- except of course in the presence of frames, since they may refer to different things.
window/document.location.reload()
- if document has POST information, browser will resubmit, and ask the user about that
history.go(0)
- ditto on POST (verify)
document.location.href=window.location.href
- You can also assign to .location (and not its .href child), but that seems to be a bit of a compatibility hack that you cannot assume will always be there.
document.location.href=window.location.replace(url)
- Similar to the last, but replaces the current history item (which is primarily handy when reloading this way)
document.location.reload()
- There is an optional parameter: true instructs the browser it should reload form the web server (which it may not necessarily do(verify)), and false means it should use the cache.
sleep()
There is no simple way of delaying execution.
There are two types of solutions. One is to calculate a time value and do a loop until 'now' is larger than it, but in most cases this will completely freeze the browser for that time, so this is usually a non-solution.
The better solution uses setTimeout. This isn't sleeping as such; instead this plays with code flow. In the following examples, something_else() will happen *before* the inner function gets triggered (by some internal javascript timer). Sequence is probably best handled via nesting one setTimeout in another.
This is also usable as a fix for a particular problem: You may have noticed that if you alter a webpage (e.g. set a 'loading...' message) and do something that blocks or is CPU-intensive, the loading message may not get displayed before the operation is done (so you probably see a brief flash before it is immediately hidden again). You can work around this using even a zero-ms setTimeout. Examples:
function onefunction() { setTimeout(function(){ //one second later setTimeout(function(){ //one second after that },1000); },1000); something_else(); } // or function onefunction() { waiting.show(); setTimeout(function(){ blocking.operation(); waiting.hide(); },0); something_else(); }
You can trigger setTimeout with both a function (which doesn't allow you to hand it data) or with code (which does, but literals, not objects/references other than with a globals/eval or DOM element trick) in a string. In both cases execution in the current function continues immediately, and the specified code after the specified time.
sort()
(webdev search for javascript+sort)
Well, not so much a problem case as something that isn't often explained in detail.
Basic sort is lexical:
sa=["11", "2", "1"] sa.sort() ...yields ["1","11","2"] // also: na=[11,2,1]; na.sort() ...yields [1,11,2]
Yes, lexical even for numbers. This presumably means it is decorate-sort-undecorate based where the decorated value is the string representation of the object.
A numerical sorter can be made with something like:
function naturalSort(a,b) { return (a-b);} na.sort(naturalSort) ...yields [1,2,11]
As the name suggests, this is also a natural sorter, because arithmetic converts numbered strings (e.g. "2"-"11"==-9) so:
sa.sort(naturalSort) ...yields ["1","2","11"]
You can apply whatever logic you want in the sort functions, sorting values arbitrarily, using external data, and whatnot. (Just try to keep it lightweight if you're ever going to be sorting large arrays). Example:
ta=[["Smith",2],["John",11],["Quu",0],["Norg",6]] ta.sort(function(a,b){return a[1]-b[1]}) ...yields [["Quu",0],["Smith",2],["Norg",6],["John",11]]
Reverse sorting can generally be done by inverting the logic:
function revNaturalSort(a,b) {return (b-a);} function revLexSort(a,b) {return (b<a);}
You can avoid this by using .reverse() on a list after soring it.
Script behaviour (particularly external)
| This article/section is a stub — probably a pile of half-sorted notes and assertions some of which may well be wrong, and not verified as a whole. Feel free to add or refine. |
When loading a page, there are several points where you may want to start executing code.
- 'at this point' (for <script> tags, relevant particularly for those in the header, but also in-page snippets)
- DOM finished loading (recently added to js libraries)
- external javascript finished loading (not easy to test)
- external images, etc. loaded (window.onload)
Notes for <script> tags:
- use type="text/javascript", not language="something" (often javascript, sometimes JavaScript, JavaScript1.1 (and other versions), or VBScript). The language tag has been deprecated since HTML4, and is not supported in XHTML.
- Some older browsers have a problem with using a <script> in the body, or anywhere else outside the head. These days you can use it, and sometimes it's quite convenient that you can.
- Some browsers have a problem with an <script> tag having an id attribute.
- Strictly speaking, if you use onsomething="" attributes you should set Content-Script-Type (a meta tag is easiest), though user agents tend to sensibly assume javascript
- the order that different types of code (head inline, body inline, external) executes in differs between browsers, and is probably not strictly defined. Each type can be deferred, which makes for more variation -- also between browsers (!)
Deferred interpretation
When you add a defer attribute to a <script> tag (defer="defer" in XHTML), you signal to the browser that it is not crucial that the script is interpreted right now, and that it can wait until the page is otherwise loaded.
This can help page load speed, although note that external js is still loaded (parsed(verify)), just not executed.
It does make the order of execution less predictable, because the order of execution of deferred objects differs between browsers.
While external javascript that is independent of other external javascript and of DOM elements can be pretty safely deferred, if you have any dependencies onto or between deferred JS files, you can break your site by assuming that execution of deferred scripts happens the same way on all browsers/versions (or, as with that it happens fast enough because external things are cached).
<script> code cannot assume libraries / library load order
| This article/section is a stub — probably a pile of half-sorted notes and assertions some of which may well be wrong, and not verified as a whole. Feel free to add or refine. |
It seems that modern browsers will load external javascript files immediately, though they do not guarantee it will be executed before the next bit of script or before window.onload (defer may force waiting, but has its limitations).
Generally, no code can assume external .js files are fully usable without explicitly testing for its presence. A lot of code should not run before some event if it references something that may not be available yet.
window.onload is possible but a potentially slow choice, while specific tests are more involved (usually a member existance test on a timer)
This also means noticable effects on load time. To reduce it:
- join scripts into as few as possible. The point is to prevent the amount of load-halting HTTP requests, and minimize their implied latency.
- ...unless they are real units. HTTP caching will kick in on later loads and for other pages (you may want to up the max-age a bit)
- use a javascript compressor. Less to load is less interruption, even if it's a minor effect
Page unresponsive until loaded
A page's javascript is unresponsive until the page is loaded; window.onload is the safest point for the browser to hand control to code that may assume other bits are present. It does mean long-loading pages won't not interact at all, even if it's just loading some prettifying backgrounds or widget images.
Check for DOM readiness
A partial solution is for code that only needs to know that the DOM is ready. The easiest solution is probably using one of the various JS libraries (mootools, jQuery, prototype), and specifically the "is the DOM ready?" event that most have fairly recently added with some cross-browser hackery.
This allows you to to hook in code that can safely assume the DOM is ready, and will execute before that huge background image loads, not after.
Check for libraries pre-window.onload
If you must have code execute as soon as possible, but only when a library is present, life is a little more complex. There's not trivial way to check whether something of a name is loaded, you have to check some effect. Many libraries will set something on the window object, though, so a simple case would be:
function myLibCheck() { if (typeof window.myLibMarker=='undefined') //it hasn't executed to set this yet setTimeout(myLibCheck,100); //in other words, re-check every 100ms until it is loaded else { //it's done //code that depends on myLib } } myLibCheck(); //kick off the checking immediately
If you want to wait for multiple libraries - together instead of firing off separate timers - you may want to make the marker easier. For example, add something like the following to each library:
if(!window.loadeds)window.loadeds=new Object();window.loadeds['myLib']=1;
...and then make your page include:
var waitfor=['advajax','nifty','myLib']; function waitForLoad() { var done=true; if(!window.loadeds)window.loadeds=new Object(); for (var i in waitfor) if (window.loadeds[waitfor[i]]===undefined) done=false; if (done) { clearInterval(window.waitTimer); someOnJSLoadCallOfYours(); } } window.onload=function() { window.waitTimer=setInterval(waitForLoad,100); } //100ms seems sensible
Note: Not thoroughly tested yet. I saw some weirdness, so I'm not even entirely sure it works as I think it should. I also edited it without testing the changes, so I could've broken it.
Notes:
- (replaces window.onload. Try to avoid replacing other interesting things or having it replaced)
- someOnJSLoadCallOfYours should not be passed into waitForLoad - that is, when it may not be defined, i.e. when it comes from something external.
- be sure you don't make a typo in the identifiers, and re-enter them when updating libraries, because if it waits for something that won't happen this breaks your page
- The code could use setTimeout (you can argue it fails neater)
snippets pause page loading
Javascript includes, when supported, allow you to shove code snippets in <script> into your page content. Older browsers (old old) will bork over this.
Various sites give you such snippets to support some feature that needs to load data from elsewhere, such as widgets from delicious, digg, and whatnot. Like any other script, they will make the 'unresponsive while loading' effect worse, particuarly if the service that data is coming from isn't blindingly fast. And for a feature that is at important to the initial render.
One way to delay such scripts seems to be to wrap the script in a <div> with display set to none and make it actually display only when the page (or DOM) is loaded. Apparently this will delay execution (in all cases?(verify)}).
Convenience functions
String
I couldn't find a whitespace strip()per, so I made my own. Pretty basic, could possibly be faster with an index-based implementation.
String.prototype.strip=function(){return this.replace(/^[\s]+/,'').replace(/[\s]+$/,'');}; //and a test alert('['+ ' a b c '.strip() +']');
Also because I needed it, a left-padder: (could use some cleaning)
//left-pads a string up to some length. (using a space. Uses value of 'ch' instead, if given. //Make this a string of length 1) String.prototype.lpad=function(to,ch) { var c=' '; if (ch) c=ch; var n=Math.max(0,to-(''+this).length); var ret=''; for (var i=0;i<n;i++) ret+=c; ret+=this; return ret; }
Calling 'foo'.lpad(5) would give " foo", calling 'bar'.lpad(6,'-') would yield "---bar".
Random things
By default you only have Math.random(), which returns 0.0 ≤ value < 1.0
To get a random integer 0≤value<n, you can do something like:
function randomInt(n) { return Math.floor(n*Math.random()) }
undefined, null and object detection in general
- undefined isn't null. Undefined is essentially 'uninitialised,' null is a value (and technically its own type). Note that:
- undefined==null will evaluate as true
- undefined===null is false (=== is identity, == is convenient-equivalence)
- Define your variables, and initialize them if sensible. You can assign things you have not defined as local (though var), but fetching things from non-defined variables will bork:
var a; var b=3; var c=null; alert(a); //will show 'undefined' alert(b); //will show '3' alert(x); //will stop execution alert(c); //would display 'null', except JS just borked.
Object detection over browser detection
Giving the user errors is annoying and when you tell a browser something it doesn't do, it may well complain. That's a problem.
You can do ye olde browser detection, but it is inexact because it is extremely hard to say what does what, since even if you detect both browser and version, you have details like that the same browser and version may be different implementations on different platforms (e.g. IE5 win vs. IE5 mac), so you would need dozens of categories of detected things, mostly the same.
Of course, this is never done with that complexity or that much consistency. That means it is often wrong, blocking supporting browsers and still allowing the odd error through. Yes, it works for IE5/IE6/FF1 you tested it under. Big whoop, it likely did anyhow and that wasn't what you were trying to fix.
The simper solution is to directly test for the things you are going to use. That means as much as the browser supports will work, and what it doesn't won't execute. For example:
if (window.focus) window.focus()
This tests whether window has a function called focus (more exactly, whether the object has a member by that name, it doesn't store something that resolves to false, and which is pretty safely assumed to be a function) before treating it as a function by trying to execute it.
See www.quirksmode.org under 'Javascript' for a longer argument.
You may have to use exceptions, for example in AJAX libraries in which you instantiate a classes by string name for the IE style. Unfortunately, some not quite out of use browsers like IE4 trip over exceptions, so it's not quite clean. There are ways around that too, actually, see this.
Unsorted
An event's related element is in the .target -- except in IE, where it is .srcElement, so you could use:
if (!e) var e=window.event; if (!e.target) e.target=e.srcElement;
However, there are more details to targeting, and some related bugs in some browsers.
New things
Xpath interface to the DOM
DOM3, so only the latest browsers; see http://www-xray.ast.cam.ac.uk/~jgraham/mozilla/xpath-tutorial.html
Better your ways...
noscript and 'this page best displayed...'
Nobody wants to see that they need another browser. Some bigger sites need to take heed here too. Many people don't know what JS is, let alone how to enable or disable it. It's even more annoying when a site decides it won't work and sends you away when it would have worked. It's usually not that hard to make things work browser-agnostically. Yes, that sometimes means avoiding the simple way that MS decided should be in IE. That's tough, but you should probably code with W3C standards in mind, common features second, nonstandard code somewhere last. (I'm probably preaching to the choir here as any webdev that cares about compatibility knows IE is the exception, not the rule.)
Rule of thumb: Don't make crucial code that may not work for any real part of your taret audience. It's just sloppy and will annoy people. In general, don't depend on scripting at all unless the context allows you to tell your users "Computer aware person, you need to enable javascript or update your browser". Preferably have your javascript add value, but don't make its absence mean a crippled web page. Preferably, have a noscript section that provides the basic functionality. But again, if people want the fancy features, they can usually be convinced to upgrade to the latest browser version. (...not necessarily to another browser, though).
It's somewhat arguable, but you can generally ignore older browsers, such as IE ≤4, FF ≤0.9, Opera ≤6 and netscape ≤5, roughly.
I say you can. Most of those are years old, negligable in market share, and not installed unless you decide to (in which case you know what you are doing, or should), have a weird admin, or windows 95. Most of the above cannot even be downloaded anymore. Anyone intent on wanting your fancy site will probably know what a browser is, so add a page that links to IE and FF and briefly explains installing them and you're nice enough.
Inline JS and strict X(HT)ML correctness
Strict XML and XHTML validators will parse script text, it will trip over characters like & and < (primarily in conditional expressions).
Perhaps the simplest way to avoid the problem is to put your code in a separate .js file.
If you must have it inline, you have to fix it. You can write the offending characters as entity references, but that's sort of odd. The somewhat cleaner solution is putting your code in a CDATA section, which saves its contents from parsing. However, since the CDATA markers have to go inside the tag, and the javascript parser gets handed the text contents of the script tag, the javascript parser will trip over those marksers. You actually have to write something that is valid in both parsers. One common, slightly awkward-looking solution is:
<cript type="whatever">/*<![CDATA[*/ script code /*]]>*/</script>
...or:
<script type="whatever"> //<![CDATA[ script code //]]> </script>
When you get away with not doing so, this is either because there are no problematic characters, or because the web browsers that allow it do so because they have historically been very forgiving. However, many other apps (say, SVG editors) don't have bunches of fix-up code and you have to given them valid XML.
Note: A much older trick was to surround all code in a script tag with <!-- -->. This guarded against very old browsers that didn't know about the script tag, since they would often fall back to just displaying the contents instead.
Don't do this. What you are actually saying is that the browser should completely ignore the contents, and some modern browsers will do so.
Other
Link click behaviour
Note: in Google, links are basic links when you have javascript disabled. When it is on, there is a script that makes each result link a call to a function that counts your click, then forwards you to the original URL.
To check: Can you make a link that pops up a small window (i.e. window.open) when clicked, but loads in a tab when control-clicked in e.g. FF?
frames
| This article/section is a stub — probably a pile of half-sorted notes and assertions some of which may well be wrong, and not verified as a whole. Feel free to add or refine. |
Getting around frames in JS nontrivial, as each frame references its own contents and is effectively its own namespace.
My current experiments suggest:
- window is a reference to the current frame
- window.frames references contained frames, including iframes, by name. If you use a name that can also be a JS symbold name, you can access them directly like window.mainframe or top.navi
- the objects you pick out are windows - they have a document, a location, etc.
- the fact frames nest makes life harder - code pretty much has to know about the frame structure
- you can use window.parent to get to the parent frame.
- you can use top to get to the root frame
See also:
http://www.quirksmode.org/js/frameintro.html
Debugging
In general you're free to set global variables, which can be useful if you're using Firebug as you can always fetch these things after the fact.
See object/hash/array contents as human-readable string (type on the key would be redundant as all array/hash keys are strings):
function see(o) { var t=''; for (i in o) t+=i+':'+typeof(o[i])+'('+o[i]+'), '; return t.slice(0,-2); } a={1:2,"3":"4"}; see(a) //gives: "1:number(2), 3:string(4)"
Stack dump / assert
You can make a simple stack-dumping assert function, to see where problems occur, or which of your testcases fails:
function assert(fact) { /* simple 'n stupid stack dump on assert failure*/ if (!fact) { try { throw new Error("Booga!"); } catch(e) { alert(e.stack); } // The throw is there purely to get a reference to an exception // and thereby the local stack description. There may be another way. } }
Semi-sorted
| This article/section is a stub — probably a pile of half-sorted notes and assertions some of which may well be wrong, and not verified as a whole. Feel free to add or refine. |
scoping details, var
In browsers, global means 'member of window'.
Variables declared outside any functions are global, regardless of whether you use var or not.
When you do not use var in a scope (practically mostly referring to functions), variables become global. When you use var, variables become local.
Number formatting
| This article/section is a stub — probably a pile of half-sorted notes and assertions some of which may well be wrong, and not verified as a whole. Feel free to add or refine. |
Not horribly flexible; mostly geared for specifing the amount of digits.
If you want something more like printf or .NET's formatting, there are a few simple (and not so simple) js libraries for this.
Number.toFixed(x) is probably most useful for currency (JavaScript 1.5)
(1.2).toFixed(2) == '1.20' (1.2).toFixed(0) == '1' (1201).toFixed(2) == '1201.00' (1201).toFixed(0) == '1201'
In earlier javascripts, you can cheat by using Math.round() (note that these are still numbers, and that this is not entirely equivalent to the above. For example, trailing zeroes would be removed):
Math.round(1.234*10)/10 == 1.2 Math.round(1.234*100)/100 == 1.23 Math.round(1.234*1000)/1000 == 1.234
Number.toPrecision(x) (JavaScript 1.5)
(1.2).toPrecision(1) == '1' (1.2).toPrecision(5) == '1.2000' (1201).toPrecision(1) == '1e+3' (1201).toPrecision(5) == '1201.0'
Number.toExponential(x) forces scientific/exponential notation even when it is not necessary
(1.2).toExponential(1) == '1.2e+0' (1.2).toExponential(5) == '1.20000e+0' (1201).toExponential(1) == '1.2e+3'
Using (locale-specific) thousand/digit separators:
(1201).toLocaleString() == '1.201' (...for me, that is)
frames
| This article/section is a stub — probably a pile of half-sorted notes and assertions some of which may well be wrong, and not verified as a whole. Feel free to add or refine. |
A frame should have a name, so that it can be targeted via <a href="foo" target="framename">
Names are handiest if they also work as javascript symbol names (so don't start with a number), and avoid reserved names like 'top' and '_blank'
A frame corresponds to a windows object, which has:
- window.document
- window.history, window.location
- window.name (empty without frames.)
- window.frames. Without frames, this is empty. With frames, it is an array of references to the window object of each child <frame>/<frameset>, in order.
- window.length, which should be the same as window.frames.length
- window.top: a reference to the outermost frame (self-reference without frames and in the top frame)
- window.parent: a reference to the direct parent window (self-reference without frames and in the top frame)
- window.self (a self-reference, apparntly for convenience)
- window.window (a self-reference, apparently purely for convenience)
Navigation:
- window.parent
- window.top
- window.childname (may be confusing to read if the names aren't clearly names of frames)
- window.frames[0] that is, index-based (may not work if src is missing from frame(verify)), probably testing for .name and/or .location.href
- window.frames['childname'] (is this standard?(verify))
Nested frames are framesets within framesets, meaning you'll see code like parent.parent, parent.frames[1], top.frames[1], frames[0].frames[1], etc.
TODO:
- check what is standard and what is just widely supported
- READ:
In-DOM storage of data
| This article/section is a stub — probably a pile of half-sorted notes and assertions some of which may well be wrong, and not verified as a whole. Feel free to add or refine. |
People commonly rely on settings variables on arbitrary DOM objects as node text or as attributes. Particularly the latter can be iffy in certain situations.
Another relatively common trick is to use <input> tags as if they are variable declarations, since they easily allow .value setting/getting (also implies you don't have to worry about escaping). (Often the input type=hidden, or type=text and using styling to hide it.
timer identifiers
setTimeout and setInterval return an identifying integer (apparently from the same pool, sometimes/always(verify)) that can be used to cancel them using clearTimer and clearInterval.
While you can call the clear funtions on nonexisting IDs and on existing ones multiple times (it generally just has no effect), a lot of javascript wants to know whether something is a reference to something currently acive. Most do so by assigning false to the variables that keep these identifiers, both initially and after doing a clearSomething(), so that you can easily test whether there is currently a reference in there:
if (runningInterval) { clearInterval(runningInterval); runninginterval=false; }
This assumes timer identifiers are always positive, non-zero integers. I have not verified this is always true. ((verify); if not, you should actually be doing an identitiy comparison)
Set-of-string operations
One general programming trick is using the fact that hash keys are per definition unique to create set operations, like the following.
However, since hash keys are always strings in JS, this isn't type-robust - this only works when all values are strings, or rather, when all values don't lose meaning when you toString() them, because that's effectively what it will do.
//Unique-ify list. (set-in-list) function unique(l) { var o=new Object(),ret=[]; for(i in l){o[l[i]]=1} for(k in o){ret.push(k)} return ret; } function union(l1,l2) { var o=new Object(),ret=[]; for(i in l1){o[l1[i]]=1} for(i in l2){o[l2[i]]=1} for(k in o){ret.push(k)} return ret; } function intersect(l1,l2) { var o=new Object(), ret=[]; for (i in l1) o[l1[i]]=1; //the value is ignored for (i in l2) if (o[l2[i]]!==undefined) ret.push(l2[i]); return ret; } function except(l1,l2) { var o=new Object(), ret=[]; for (i in l1) o[l1[i]]=1; for (i in l2) delete(o[l2[i]]); for (i in o) ret.push(i); return ret; }
Array member tests
No cleverness, just a simple and stupid iteration thing.
Note that as per javascript's equivalence tests ('1'==1 being true and such), this may be fuzzier than you want it to be. You can require the type to be the same using the second parameter.
a=['1',2,6]; a.contains(2); //true '1'.in(a); (1).in(a,true); //type not identical, so false (1).in(a); //no type check, so true
Code:
function in_test(ary,stricttype) { for (var i=0; i<ary.length; i++) { if (ary[i]==this) if (stricttype) return typeof(ary[i])==typeof(this) else return true; } return false; } String.prototype.in = in_test; Number.prototype.in = in_test; //you could add it on Boolean, Date, but would you use it? Array.prototype.contains = function(o,stricttype) { for (var i=0; i<this.length; i++) { if (this[i]==o) if (stricttype) return typeof(this[i])==typeof(o) else return true; if (this[i]==o) return true; } return false; }
Text escaping and encoding
(See also Webdev_notes#Escaping)
URL escaping, UTF8 encoding
escape() does the %20%3D thing, but only for ASCII characters. Unicode is encoded in a javascript-specific way (e.g. U+2222 encodes as %u2222) that is non-standard and most servers will not understand.
In javascript 1.5 and later, you have two functions that encode as UTF8 before escaping, which is what most servers with unicode support may expect (see also cp1252, though):
encodeURI(), in which the escape step does not %-escape ":", "/", ";", and "?" so that the result is still formatted/usable as a URL.
encodeURIComponent(), which %-escapes everything. Use this when shoving URLs into URL query parameters.
Note that various code has special treatment for URLs in URLs (particularly if they are lone parameters), so you should always check the specs. For example, look at the differences in syndication 'Add to' links.
UTF8 encoding without URL escaping does not exist in Javascript, but consists of simple operations. You could implement your own, or use someone else's, such as this UTF8 encoder and decoder.
other escaping
| This article/section is a stub — probably a pile of half-sorted notes and assertions some of which may well be wrong, and not verified as a whole. Feel free to add or refine. |
HTML escaping (that is to say, & into &, < into <, and > into >) can be done in a few ways. One hack you see now and then is to leverage browser innards by using innerHTML and letting it sanitize the string, then read out the same thing, which is probably faster than a few replaces in a row, but also counts on browser behaviour.
A very basic implementation (which may well be more portable) would be:
function escape_nodetext(s) { return s.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>'); }
In attributes, you would also want to replace ", and possibly '.
function escape_attr(s) { return s.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>') .replace(/"/g, '"').replace(/'/g, '''); }
Bookmarks/favorites
While you can't change the bookmarks from scripting (which is a good thing, securitywise), you can prompt to add a bookmark. There is no standard, each browser has its own way.
function addToBookmarks(url,title) { if (window.external && window.external.AddFavorite) window.external.AddFavorite(url,title); // IE4 and later else if (window.sidebar && window.sidebar.addPanel) window.sidebar.addPanel(title,url,''); //Gecko/firefox } //use e.g. like: addToBookmarks(window.document.location, window.document.title);
Of course, you can check for IE and gecko another way.
See also:
- http://developer.mozilla.org/en/docs/DOM:window.sidebar
- http://msdn2.microsoft.com/en-us/library/ms535926(VS.85).aspx
innerHTML versus other content setters
innerHTML is a fast way to set contents under a given DOM element, and convenient in that it allows you to enter elements via raw HTML.
However, innerHTML, outerHTML (and also innerText and outerText) is not part of the DOM or any standard; they are microsoft additions with no public standard. While the method itself has been adopted by every serious browser, the lack of standard means the behaviour/semantics differ in some details.
In general, the most compatible way is to use only standard DOM methods, by setting nodeValue and using createElement and createTextNode for any new child elements. You may wish to use some library to build a DOM tree from a bare html string (basically doing the work that the implementations of innerHTML do, but now in script so it happens consistently across browsers). One way is using Dan Webb's dombuilder.js, and larger libraries like jQuery, Prototype and such also have functions for this.
One specific bug is that TEXTAREAs in IE eat newlines in text data when you you set via innerHTML. innerText was made for this case, but this is an IE-only function.
In the case of textarea, .value seems more or less equivalent to this(verify).
See also:
- http://www.quirksmode.org/dom/innerhtml.html (speed comparison)
- http://developer.mozilla.org/en/docs/DOM:element.innerHTML
- http://msdn2.microsoft.com/en-us/library/ms533897.aspx
Tools
Code compressors

