1: use object-oriented Javascript
Believe it or not, you can use the object-oriented method to write JavaScript. In this way, you can get better reusable code, organize objects, and dynamically load objects. The following is the shopping cart of the Javascript version, followed by the equivalent Java code.
Function cart (){
This. Items = [];
}
Function item (ID, name, DESC, price )){
This. ID = ID;
This. Name = Name;
This. DESC = DESC;
This. Price = price;
}
// Create an instance of the cart and add an item
VaR cart = new cart ();
Cart. Items. Push (new item ("ID-1", "paper", "Something you write on", 5 ));
Cart. Items. Push (new item ("ID-1", "pen", "Something you write with", 3 );
VaR total;
While (var l; L <cart. Items. length; l ++ ){
Total = total + cart. items [l]. price;
}
The above cart object provides basic support for maintaining the internal array of item objects.
The equivalent Java object representation of the shopping cart is as follows.
Import java. util .*;
Public class cart {
Private arraylist items = new arraylist ();
Public arraylist getitems (){
Return items;
}
}
Public class item {
Private string ID;
Private string name;
Private string DESC;
Private double price;
Public item (string ID, string name, string DESC, double price ){
This. ID = ID;
This. Name = Name;
This. DESC = DESC;
This. Price = price;
}
Public String GETID (){
Return ID;
}
Public String getname (){
Return name;
}
Public String getdesc (){
Return DESC;
}
Public float getprice (){
Return price;
}
}
The preceding example shows the server-side object representation of a shopping cart. This object needs to be saved in httpsession by a JSP, Servlet, or JSF managed bean. You can use ajax to add a product to the shopping cart or retrieve the current status.
2. Organize JavaScript objects using the object hierarchy
In JavaScript, object names may conflict. In Java, you can use the package name to prevent name conflicts. Unlike Java, JavaScript does not provide the package name, but you can create it by yourself. When writing components, you can use the object and object hierarchy to organize related objects to prevent name conflicts. The following example creates a top-level object blueprints. In a sense, it is equivalent to the namespace of the relevant object. These objects are set as attributes of the parent object.
// Create the base blueprints object if it does not exist.
If (! Blueprints ){
VaR blueprints = new object ();
}
Blueprints. Cart = function (){
This. Items = [];
This. additem = function (ID ){
Items. Push (new item (ID );
}
Function item (ID, qty ){
This. ID = ID;
This. qty = qty;
}
}
// Create an instance of the cart and add an item
VaR cart = new blueprints. Cart ();
Cart. additem ("ID-1", 5 );
This technology can prevent naming conflicts. It is a good practice to use this code where naming conflicts may occur.
3: Use prototype attributes to define shared behaviors and extended objects
Prototype properties are a language function of JavaScript. All objects have this property. If a property cannot be found in the current object, the property parsing function in Javascript will view the value of the prototype property. If the object value defined as a prototype object does not contain this attribute, the value of its prototype attribute is checked. The prototype property chain (layered structure) is usually used to provide inheritance in Javascript objects. The following example shows how to add a behavior to an existing object using the prototype property.
Function cart (){
This. Items = [];
}
Function item (ID, name, DESC, price )){
This. ID = ID;
This. Name = Name;
This. DESC = DESC;
This. Price = price;
}
Function smartcart (){
This. Total;
}
Smartcart. Prototype = new cart ();
Smartcart extends the cart object, inherits its attributes, and adds a total attribute. Next, we will add some simple functions to cart to add products and calculate the total price. Although functions can be directly added to the smartcart object, this will lead to the creation of a new function for each smartcart instance. In JavaScript, a function is an object. Therefore, for objects that need to be created for many instances, sharing instance behavior can save resources.
The following Code declares the shared calcualtetotal and additem functions and adds them as attributes of the smartcart prototype members.
Cart. Prototype. additem = function (ID, name, DESC, price ){
This. Items. Push (new item (ID, name, DESC, price ));
}
Cart. Prototype. calculatetotal = function (){
For (var l = 0; L <this. Items. length; l ++ ){
This. Total = This. Total + this. items [l]. price;
}
Return this. Total;
}
// Create an instance of the cart and add an item
VaR cart = new smartcart ();
Cart. additem ("ID-1", "paper", "Something you write on", 5 );
Cart. additem ("ID-1", "pen", "soemthing you write with", 3 );
Alert ("total is:" + cart. calculatetotal ());
As you can see, object extension is very simple. In this example, there is only one calcualtetotal instance, and the additem function is used to share among all instances of the smartcart object. Note that the items scope is still this. items, even if these functions are separately declared from the smartcart object. When new prototype functions are executed, they are located in the scope of the smartcart object.
We recommend that you use the prototype attribute to define shared behavior when many object instances may occur, because this reduces the number of objects in JavaScript and completely separates behavior from data by using this attribute. Prototype attributes are also ideal for providing default values for objects (not discussed here ). There are many other features that can be implemented through prototype attributes, but this is beyond the scope of this article. For more information, see the "Resources" section in this article.
4: stores view-specific statuses in JavaScript and cross-page statuses on servers
In the previous example, we introduced how to use the shopping cart as a server object and a client object. It is difficult to store the status on the client or on the server. If you design the Javascript client as a single-page application, it may be appropriate to use the cart only on the client. In this case, the shopping cart of the Javascript version may only interact with the server when it is checked out.
Generally, JavaScript objects should be used to store view States related to specific pages. Remember, JavaScript objects are specific to HTML pages. If you press the "reload" button, restart/crash the browser, or navigate to another page, these objects will be lost.
When the scope of a Java object is httpsession, the cross-page status should be stored on the server. When refreshing and loading pages, the client and server objects should be synchronized.
If you need to develop an Ajax client offline (for example, on a plane trip), you can use multiple methods to store the status on the client, but none of these are the standard methods. Dojo provides the dojo. Storage API to store up to KB of offline content on the Javascript client. With the emergence of the client storage standard, we believe that the API will be modified accordingly to support this standard. If the state to be saved is confidential, or multiple computers need to access the state, you should consider storing the state on the server.
5. Write reusable Javascript
Unless absolutely necessary, JavaScript should not be bound to a specific component. Do not encode data in parameterized functions. The following example shows a reusable AutoComplete JavaScript function.
<SCRIPT type = "text/JavaScript">
Dosearch (serviceurl, srcelement, targetdiv ){
VaR targetelement = Document. getelementbyid (srcelement );
VaR targetdivelement = Document. getelementbyid (targetdiv );
// Get completions Based on serviceurl and srcelement. Value
// Update the contents of the targetdiv Element
}
</SCRIPT>
<Form onsubmit = "Return false;">
Name: <input type = "input" id = "AC_1" AutoComplete = "false" onkeyup = "dosearch ('namesearch', 'ac _ 1', 'div _ 1 ') ">
City: <input type = "input" id = "ac_2" AutoComplete = "false" onkeyup = "dosearch ('citysearch', 'ac _ 2', 'div _ 2 ') ">
<Input type = "button" value = "Submit">
</Form>
<Div class = "complete" id = "div_1">
</Div>
<Div class = "complete" id = "div_2">
</Div>
The dosearch () function in the preceding example can be reused because it is parameterized using the element string ID, service URL, and the <div> to be updated. This script can be used by other pages or applications.
6. Use object types as flexible function parameters
The object type is defined using curly brackets ({}). It contains a set of key values separated by commas (,), which is very similar to the ing in Java.
{Key1: "stringvalue", key2: 2, key3: ['blue', 'green', 'yellow']}
The preceding example shows an object type that contains strings, numbers, and string arrays. As you can imagine, the object type is very easy to use because it can be used as a common object to PASS Parameters for functions. If you select to use more attributes in the function, the function signature will not change. Consider using the object type as the method parameter.
Function dosearch (serviceurl, srcelement, targetdiv ){
VaR Params = {service: serviceurl, method: "Get", type: "text/XML "};
Makeajaxcall (Params );
}
Function makeajaxcall (Params ){
VaR serviceurl = Params. Service;
...
}
Note that you can pass anonymous functions by using object types, as shown in the following example:
Function dosearch (){
Makeajaxcall ({serviceurl: "foo", method: "Get", type: "text/XML", callback: function () {alert ('call done ');}});
}
Function makeajaxcall (Params ){
VaR Req = // getajax request;
Req. Open (Params. serviceurl, Params. method, true );
Req. onreadystatechange = Params. Callback;
...
}
Do not confuse object types with JSON with similar syntax.
7: completely separate content, CSS, and JavaScript
The user interface of a rich web application is composed of content (html/XHTML), style (CSS), and JavaScript. Javascript is crucial because user operations (such as mouse clicking) call it and it can process the content. By separating CSS styles from JavaScript, you can make the code easier to manage and customize and make it more readable. We recommend that you put CSS and Javascript in a separate file.
If HTML is rendered from Java-based components (such as JSP, Servlet, or JSF Renderer), you may need to output the style and JavaScript (as shown below) on each page ).
<Style>
# Styles
</Style>
<SCRIPT type = "text/JavaScript">
// JavaScript logic <SCRIPT>
<Body> The quick brown fox... </body>
If content is embedded in each page, the bandwidth loading overhead may occur each time the page is loaded. By referencing content rather than Embedding content (as shown below), you can cache JavaScript and CSS files and reuse them on different pages.
<LINK rel = "stylesheet" type = "text/CSS" href = "cart.css">
<SCRIPT type = "text/JavaScript" src = "cart. js">
<Body> The quick brown fox... </body>
You can map links to static resources on the server or to JSP, Serlvet, or JSF components that dynamically generate resources. If the JSF component is developed, consider using shale remoting, which provides some basic classes that provide core functions for writing scripts/CSS links, and can even access resources in the jar file of the JSF component.
In JavaScript code, use element when dynamically changing the element style. classname instead of element. setattribute ("class", style_class), because most browsers support element. classname (this is also the most effective way to support ie style changes ).
In the tag library definitions of JavaServer faces (JSF) and pure Java tag libraries, the attribute "class" cannot be used to specify styles, because all Java objects contain the getclass () method, this method cannot be overwritten. Use the attribute name "styleclass" instead ".
8: Avoid storing static content in Javascript
Like in other source code, JavaScript should use the minimal static html/XHTML content. This makes it easier to manage the updated static content. You may want to upgrade the component content without changing the source code. Static content can be extracted from the code. The method is similar to that when resourcebundles is used in Java, or an Ajax request can be used for loading. This design provides a method to create a localized interface.
The following XML documents resources. xml and code snippets show how to extract static resources from JavaScript code.
<Resources>
<Resource id = "foo">
<Value> bar </value>
</Resource>
<Resource id = "fooy">
<Value> fooy </value>
<Value> bar </value>
</Resource>
</Resources>
By ing the HTML page to the window. onload function to load the HTML page, the Javascript load function is loaded.
Function load (){
// Load the first set of images
// Get resources. XML with an Ajax request
// And give the responsexml to processresults ()
}
Function Resource (ID, values ){
This. Name = ID;
This. value = values. Join ();
This. Values = values;
}
VaR resources = new object ();
// Parse the XML returned from an Ajax request
Function processresults (responsexml ){
VaR resourceelements = responsexml. getelementsbytagname ("resource ");
For (var l = 0; L <resourceelements. length; l ++ ){
VaR resourceelement = resourceelements [l];
VaR id = resourceelement. getattribute ("ID ");
VaR valueelements = resourceelement. getelementsbytagname ("value ");
VaR values = [];
For (var vl = 0; VL <valueelements. length; VL ++ ){
VaR value = valueelements [VL]. firstchild. nodevalue;
Values. Push (value );
}
Resources [ID] = new resource (ID, values );
}
Alert ("foo =" + resources ['fooy']. value );
}
This code analyzes the preceding XML document and puts each resource into a resource object. You can use JSON to send the same data. However, using XML may be a good method. Here, if you choose to send localized content in XML format, it is easy to provide a method to support localized content.
Similar to Gui components, when static content may come from external resources, be very careful when setting the layout size statically, because the new content may exceed the boundaries of the component.
9: Use element. innerhtml with caution
You may prefer to use element. innerhtml instead of the DOM style element. appendchild (), because element. innerhtml is much easier to program and the browser processes it much faster than using Dom APIs. However, you must understand the shortcomings related to this method.
If you choose to use element. innerhtml, try writing JavaScript that generates the minimal HTML. CSS should be used to improve the representation. Remember to always try to separate the content from the representation. Before resetting element. innerhtml, ensure that the event listening program is not registered in the existing innerhtml of the element because it may cause memory leakage. Remember, when the content is replaced, DOM elements in element. innerhtml will be lost, and references to these elements will also be lost.
Consider using Dom APIs (such as element. appendchild () to dynamically create elements in JavaScript. Dom APIs are standard APIs. When creating elements, they are programmed to access these elements as variables, making it easier to avoid using element. innerhtml problems such as memory leakage or loss of reference. That is to say, it is important to remember that using Dom to create a table in IE may cause problems, because the APIs in IE do not follow Dom. For the required APIs, see the msdn document on the table. Adding elements other than tables in IE does not cause any problems.
10: Disable with caution
Disabling easy creation may cause problems in some cases. Developers who are used to object orientation may tend to bind the behavior of objects with objects. The following example shows how to disable Memory leakage.
Function badcart (){
VaR total;
VaR items = [];
This. additem = function (text ){
VaR cart = Document. getelementbyid ("cart ");
VaR itemrow = Document. createelement ("Div ");
VaR item = Document. createtextnode (text );
Itemrow. appendchild (item );
Cart. appendchild (item );
Itemrow. onclick = function (){
Alert ("clicked" + text );
}
}
}
So where is the error in this example? Additem references DOM nodes that are not in the badcart scope. The anonymous "onclick" handler function keeps references to itemrow and does not allow garbage collection, unless we explicitly set itemrow to null. The following code in goodcart will solve this problem:
Function goodcart (){
VaR total;
VaR items = [];
This. additem = function (text ){
VaR cart = Document. getelementbyid ("cart ");
VaR itemrow = Document. createelement ("Div ");
VaR item = Document. createtextnode (text );
Itemrow. appendchild (item );
Cart. appendchild (item );
Itemrow. onclick = function (){
Alert ("clicked" + text );
}
Itemrow = NULL;
Item = NULL;
Cart = NULL;
}
}
Set itemrow to delete external references from anonymous functions that are set as itemrow. onclick handlers. A good practice is to clean up and set item and cart to null to recycle all content. Another solution to prevent memory leakage is to do not use external functions to replace the anonymous functions in badcart.
If disabled, do not use closed local variables to keep references to browser objects (such as Dom-related objects), because this may cause memory leakage. After deleting all references to an object, garbage collection should be performed on the object. For more information, see disable javascript.