JavaScript Tips

  • Revision slug: JavaScript_Tips
  • Revision title: JavaScript Tips
  • Revision id: 77679
  • Created:
  • Creator: namusyaka
  • Is current revision? No
  • Comment 27 words added

Revision Content

XUL Tips

  • When inserting code with an XUL overlay, wrap functions and variables inside an object with a unique name to avoid conflicting with existing or future function and variable names.
var UniqueName = {
  _privateMember: 3,
  publicMember: "A string",

  init: function UN_init() {
    this.doSomething(this.anotherMember);
  },

  doSomething: function UN_doSomething(aParam) {
    alert(aParam);
  }
};

XPConnect

  • Don't use object methods and properties more than you have to. It is often faster to store the result in a temporary variable.
  • Don't call methods that you don't have to. For instance, for a single window, windowManager.getEnumerator(aType).hasMoreElements() may be replaced with windowManager.getMostRecentWindow(aType) != null.
  • Don't query interfaces unless you need to access methods and properties of that interface. You do not have to query interfaces to compare objects, nor to pass objects as parameters. (Both of these are required in C++).
  • Don't call QueryInterface unless you expect to succeed. Instead, use instanceof, e,g,:
if (target instanceof Components.interfaces.nsIRDFResource)
  return target.Value;
if (target instanceof Components.interfaces.nsIRDFLiteral)
  return target.Value;
return null;
  • Don't test the return value of QueryInterface, it always returns the original variable if it succeeds. XPConnect knows all about tearoffs and modifies the object that you QueryInterface or instanceof to cache all its known interfaces.
  • Often when passing an object to an XPCOM method it is helpful if the object you pass is an XPCOM object, so that the C++ method access a C++ object. However this is not always necessary or desirable. For instance the offline observer declared above is a JavaScript object that is registered with an XPCOM object, so that the call back from XPCOM executes the JavaScript method. Some XPCOM methods expect an object that implements several interfaces thus requiring you to write a QueryInterface method. However in JavaScript this is quite simple even in the case of a weak reference which in C++ requires a helper class:
var weakObserver = {
  QueryInterface: function QueryInterface(aIID) {
    if (aIID.equals(Components.interfaces.nsIObserver) ||
        aIID.equals(Components.interfaces.nsISupportsWeakReference) ||
        aIID.equals(Components.interfaces.nsISupports))
       return this;
    throw Components.results.NS_NOINTERFACE;
  },
  observe: function observe(aSubject, aTopic, aState) {
  }
}
  • When declaring XPCOM methods try to use the same names for method parameters as are used in the interface definition.

DOM elements

  • DOM elements are just XPCOM objects with some of the interfaces precached.
  • Don't call getAttribute to see if an attribute exists, call hasAttribute instead.
  • Prefer to loop through childNodes rather than using first/lastChild with next/previousSibling. But prefer hasChildNodes() to childNodes.length > 0. Similarly prefer document.getElementsByTagName(aTag).item(0) != null to document.getElementsByTagName(aTag).length > 0.
  • Prefer to use localName rather than tagName.
  • XUL elements have many of the attributes mapped to properties. This was done for a reason, so use them! The properties are:
    • id
    • align
    • dir
    • flex
    • orient
    • pack
    • observes
    • contextMenu
    • tooltip
    • width
    • height
    • minWidth
    • minHeight
    • maxWidth
    • maxHeight
    • persist
    • left
    • top
    • datasources
    • ref
    • tooltipText
    • statusText
    • allowEvents
  • XUL also maps the ordinal attribute but this defaults to "1" if it is not present.
  • XUL also maps the class attribute, but unfortunately class is a reserved identifier, so the property is named className. (The property could have been implemented as {{ mediawiki.external('"class"') }} but that just looks silly.)
  • XUL also maps the hidden and collapsed attributes to properties, but note that these are boolean properties whereas the above list are all string properties.
  • XUL also maps other useful properties and methods using XBL bindings; these vary from element to element.
  • For best performance give ids to all important elements. However in addition to locating elements by tag name XUL also allows you to locate an element by attribute, starting at any element in the document.
  • Don't forget to use DOM constants such as event.keyCode == KeyEvent.DOM_VK_RETURN rather than event.keyCode == 13.Now, DOM hasn't supported the KeyEvent Constant(other modern browser hasn't supported.). Therefore, you should use number literal.

References

{{ languages( { "ja": "ja/JavaScript_style_guide" } ) }}

Revision Source

<h2 name="Function_and_variable_naming">XUL Tips</h2>
<ul> <li>When inserting code with an XUL overlay, wrap functions and variables inside an object with a unique name to avoid conflicting with existing or future function and variable names.</li>
</ul>
<pre class="eval">var UniqueName = {
  _privateMember: 3,
  publicMember: "A string",

  init: function UN_init() {
    this.doSomething(this.anotherMember);
  },

  doSomething: function UN_doSomething(aParam) {
    alert(aParam);
  }
};
</pre>
<h2 name="XPConnect">XPConnect</h2>
<ul> <li>Don't use object methods and properties more than you have to. It is often faster to store the result in a temporary variable.</li> <li>Don't call methods that you don't have to. For instance, for a single window, <code>windowManager.getEnumerator(aType).hasMoreElements()</code> may be replaced with <code>windowManager.getMostRecentWindow(aType) != null</code>.</li> <li>Don't query interfaces unless you need to access methods and properties of that interface. You do not have to query interfaces to compare objects, nor to pass objects as parameters. (Both of these are required in C++).</li> <li>Don't call <code>QueryInterface</code> unless you expect to succeed. Instead, use <code>instanceof</code>, e,g,:</li>
</ul>
<pre>if (target instanceof Components.interfaces.nsIRDFResource)
  return target.Value;
if (target instanceof Components.interfaces.nsIRDFLiteral)
  return target.Value;
return null;
</pre>
<ul> <li>Don't test the return value of <code>QueryInterface</code>, it always returns the original variable if it succeeds. XPConnect knows all about tearoffs and modifies the object that you <code>QueryInterface</code> or <code>instanceof</code> to cache all its known interfaces.</li> <li>Often when passing an object to an XPCOM method it is helpful if the object you pass is an XPCOM object, so that the C++ method access a C++ object. However this is not always necessary or desirable. For instance the offline observer declared above is a JavaScript object that is registered with an XPCOM object, so that the call back from XPCOM executes the JavaScript method. Some XPCOM methods expect an object that implements several interfaces thus requiring you to write a <code>QueryInterface</code> method. However in JavaScript this is quite simple even in the case of a weak reference which in C++ requires a helper class:</li>
</ul>
<pre>var weakObserver = {
  QueryInterface: function QueryInterface(aIID) {
    if (aIID.equals(Components.interfaces.nsIObserver) ||
        aIID.equals(Components.interfaces.nsISupportsWeakReference) ||
        aIID.equals(Components.interfaces.nsISupports))
       return this;
    throw Components.results.NS_NOINTERFACE;
  },
  observe: function observe(aSubject, aTopic, aState) {
  }
}
</pre>
<ul> <li>When declaring XPCOM methods try to use the same names for method parameters as are used in the interface definition.</li>
</ul>
<h2 name="DOM_elements">DOM elements</h2>
<ul> <li>DOM elements are just XPCOM objects with some of the interfaces precached.</li> <li>Don't call <a href="/en/DOM/element.getAttribute" title="en/DOM/element.getAttribute">getAttribute</a> to see if an attribute exists, call <a href="/en/DOM/element.hasAttribute" title="en/DOM/element.hasAttribute">hasAttribute</a> instead.</li> <li>Prefer to loop through childNodes rather than using first/lastChild with next/previousSibling. But prefer hasChildNodes() to <code>childNodes.length &gt; 0</code>. Similarly prefer <code>document.getElementsByTagName(aTag).item(0) != null</code> to <code>document.getElementsByTagName(aTag).length &gt; 0</code>.</li> <li>Prefer to use localName rather than tagName.</li> <li>XUL elements have many of the attributes mapped to properties. This was done for a reason, so use them! The properties are: <ul> <li>id</li> <li>align</li> <li>dir</li> <li>flex</li> <li>orient</li> <li>pack</li> <li>observes</li> <li>contextMenu</li> <li>tooltip</li> <li>width</li> <li>height</li> <li>minWidth</li> <li>minHeight</li> <li>maxWidth</li> <li>maxHeight</li> <li>persist</li> <li>left</li> <li>top</li> <li>datasources</li> <li>ref</li> <li>tooltipText</li> <li>statusText</li> <li>allowEvents</li> </ul> </li> <li>XUL also maps the <code>ordinal</code> attribute but this defaults to "1" if it is not present.</li> <li>XUL also maps the <code>class</code> attribute, but unfortunately <code>class</code> is a reserved identifier, so the property is named <code>className</code>. (The property could have been implemented as <code>{{ mediawiki.external('"class"') }}</code> but that just looks silly.)</li> <li>XUL also maps the <code>hidden</code> and <code>collapsed</code> attributes to properties, but note that these are boolean properties whereas the above list are all string properties.</li> <li>XUL also maps other useful properties and methods using XBL bindings; these vary from element to element.</li> <li>For best performance give ids to all important elements. However in addition to locating elements by tag name XUL also allows you to locate an element by attribute, starting at any element in the document.</li> <del>Don't forget to use DOM constants such as <code>event.keyCode == KeyEvent.DOM_VK_RETURN</code> rather than <code>event.keyCode == 13</code>.</del><ins>Now, DOM hasn't supported the KeyEvent Constant(other modern browser hasn't supported.). Therefore, you should use number literal.</ins>
</ul>
<h2 name="References">References</h2>
<ul> <li>This was started as a reprint of <a class="external" href="http://neil.rashbrook.org/JS.htm" title="http://neil.rashbrook.org/JS.htm">Neil's guide</a></li> <li>Some more current info on this <a class="external" href="http://autonome.wordpress.com/2006/03/24/">blog post</a></li>
</ul>
<p>{{ languages( { "ja": "ja/JavaScript_style_guide" } ) }}</p>
Revert to this revision