JavaScript coding basics

From AheadOffice development documentation

Jump to: navigation, search

Contents

Some things everyone must know

Namings

Like in Java, "native syntax" in JavaScript means using of "camel-syntax".

doSomethingGood(); // Function
var someGoodVariable = 0; // Stand-alone variable
SomeObject = new SomeConstructor; // Object and constructor
SomeObject.property = 'Test'; // Property of object
SomeObject.doAnother(); // Method of object

Abbreviatures case must not be altered. E.g. JavaScript function encodeURIComponent().

Functions, variables as objects

Almost everything in JavaScript is Object. Keep this always in mind.

Functions

Each function is an object. Each function is always a method also. If you declare a "standalone" function, this function is registered as a method of window object.

function test(){
  alert(1);
}
window.test(); // '1'

Variables

Each variable is an object. Each variable is always a property also. If you declare a "standalone" variable, this variable is registered as a property of window object.

test = 1;
alert(window.test); // '1'

Almost everything in JavaScript is Object. Keep this always in mind.

Objects

Take in mind, that JavaScript is an object-oriented language. Developing a JS application using C, PHP, Perl and other imperative (non-object-riented) styles produces confusing and hard-to-understand code. The real hell is scaling such an application.

Creating

Prototypes

Prototype is one of the milestones, which JavaScript's OOP is based on. Any created object has prototype, even if you hadn't obviously specified that.

Prototype is an object, which properies and methods are assigned to the resulting object. In case when it has no obviously specified prototype, JavaScript's Object instance is used instead.

We'll return to prototypes later.

From 'Object'

JavaScript has built-in object, called "Object". All objects, handled by JavaScript has it as the final ancestor.

var MyObj = new Object;
MyObj.aaa = function(){ // new method for our object
  alert(1);
}
MyObj.bbb = '1'; // registering property

From JSON

var A = {
	b : 'b',
	c : 'c',
	d : function(msg){alert(msg)}
}

You can read more about JSON

From constructor

Constructor is a special function, that is employed to create a new object using new keyword. Custom keyword this is used for access to created object instance

var MyConstructor = function(){
	this.message = 'hello';
	this.printMessage = function(){
		aler(this.message);
	}
}
var Example = new MyConstructor;
alert(Example.message);
// 'hello'
Example.printMessage();
// 'hello'

Prototypes

Glad to see prototypes again. Prototype is a good way to classify objects by their parents. Abstractly - prototype is parent of an object parent, or grandfather of the object :)

How does it work

Prototypes are normally utilized this way:

  1. Create an object with your constructor;
  2. JavaScript evaluates constructor function of the object;
  3. JavaScript evaluates constructor of prototype function to a temporary object;
  4. JavaScript copies all methods and properties of the temporary object to the main object, if constructor has no such.

A short example

The best way to understand is to examine the code below:

var Barebone = new Object; // Created object - barebone(case with motherboard inside)
// Fill some properties
 
Barebone.powerUnit = '300W';
Barebone.motherBoard = 'ASUS P5 Series';
 
// Now it is a good idea to assemble my computer from the barebone
 
var MyComputer.prototype = new Barebone;
MyComputer.prototype.CPU = 'Intel Core 3 Quad 6000 ';
MyComputer.prototype.memory = 'Corsair TWIN 2x8Gb';
MyComputer.prototype.video = '2xNvidia 8800 Ultra SLI';
 
// Create
 
coolComp = new MyComputer; // for me
wifesComp = new MyComputer; // and for my wife

Let us see what has been done.

var Barebone = new Object; // Created object - barebone(case with motherboard inside)
 
Barebone.powerUnit = '300W';
Barebone.motherBoard = 'ASUS P5 Series';

Team of your computer shop assembles the barebone system. They put it in price

var MyComputer.prototype = new Barebone;

You call to these guys and explain that you'd like to create a configuration based on their barebone.

MyComputer.prototype.CPU = 'Intel Core 3 Quad 6000 ';
MyComputer.prototype.memory = 'Corsair TWIN 2x8Gb';
MyComputer.prototype.video = '2xNvidia 8800 Ultra SLI';

You add that your configuration must include some additional hardware options also.

Your computer is NOT ready! By now this is only a piece of paper with a configuration written on it

coolComp = new MyComputer;
wifesComp = new MyComputer;

After that you order two pieces of that configuration and the guys assemble it for you.

Extending ready objects with prototype

For example, you have a good idea to put methods directly to needed object. E.g. you need to create ltrim() method, wich trims strings from the left. So the object can be easily extended with prototype:

String.prototype.lTrim = function() {
 
	var re = /\s*((\S+\s*)*)/;
	return this.replace(re, "$1");
 
}

now the result be

var testStr = '      test';
 
alert(testStr);
// 	'      test'
alert(testStr.lTrim());
// 'test'

JSON

 JSON (JavaScript Object Notation) is a lightweight computer data interchange format. It is a text-based, human-readable format for representing objects and other data structures and is mainly used to transmit such structured data over a network connection (in a process called serialization).

Supported data types, syntax and example

JSON's basic types are

  • Number (integer, real, or floating point)
  • String (double-quoted Unicode with backslash escapement)
  • Boolean (true and false)
  • Array (an ordered sequence of values, comma-separated and enclosed in square brackets)
  • Object (collection of key/value pairs, comma-separated and enclosed in curly brackets)
  • null

The following example shows JSON's representation of an object that describes a person. The object has string fields for first name and last name, contains an object representing the person's address, and contains a list of phone numbers (an array).

{
    "firstName": "John",
    "lastName": "Smith",
    "address": {
        "streetAddress": "21 2nd Street",
        "city": "New York",
        "state": "NY",
        "postalCode": 10021
    },
    "phoneNumbers": [
        "212 732-1234",
        "646 123-4567"
    ]
}

Suppose the above text is contained in the JavaScript string variable JSON_text. Since JSON is a subset of JavaScript's object literal notation, one can then recreate the object describing John Smith with a simple eval():

var p = eval("(" + JSON_text + ")");

and the fields p.firstName, p.address.city, p.phoneNumbers[0] etc. are then accessible. Parentheses are necessary because bare objects are not valid JavaScript.

Arrays

To declare array

[1,2,3,'test']

Security

In general, eval() should only be used to parse JSON if the source of the JSON-formatted text is completely trusted; the execution of untrusted code is obviously dangerous. JSON parsers are available to process JSON input from less trusted sources.

Compatibility with other languages

JSON is compatible format; many languages has libraries to support JSON. PHP, Perl, Python, C/C++ and many others. In PHP 5.2.0 and later, JSON extension is enabled by default. Visit JSON official site to see details.


DOM operations

DOM operations vs innerHTML

A lot of developers are in love with innerHTML. But it is a good style to use DOM functions instead. innerHTML usage process can be described this way:

  1. Browser parses all data inside innerHTML;
  2. then it builds DOM tree, basing on innerHTML code;
  3. browser replaces children of selected node with this DOM tree.

Also, all events applied to DOM model of selected node are broken after assigning innerHTML. So it's a good idea to build DOM tree directly.

Read about DOM speed issues.


=== Clearing object with DOM ===

There is a simple way to clear node via DOM:

function(obj){
	var cl;
	while(cl = obj.firstChild)
		obj.removeChild(cl);
}

Events

You can setup event of an element in 3 ways:

Hanging event via attribute

Write something like:

<a href="#" onclick="myFunction()">Click me</a>

This is the worst way. Let us see why:

  1. Each time the event is called, browser calls eval() to on**** attribute. It is slow.
  2. Because of eval(), function called from attribute must be in global visibility scope
  3. It's not easy to debug

Try not to do this.

Hanging event via on**** properties

This way is better:

someElement.onclick = myFunction;

or

someElement.onclick = function(){ doSomething() };

This works in such way: event function is attached to element, and is called when the event happens

this keyword

When hanging event using on**** properties, this keyword refers to the element which caused the event. It is convenient in many cases:

someElement.setAttribute('title','title_1');
someElement.onclick = function(){ alert(this.getAttribute('title')); };
// -> receieved click
// 'title_1'
someElement.setAttribute('title','title_2');
// -> receieved click
// 'title_2'

Event function can be easily reloaded:

someElement.setAttribute('title','title_1');
 
someElement.onclick = function(){ alert(this.getAttribute('title')); };
 
// -> receieved click
// 'title_1'
 
someElement.onclick = function(){  }
 
// -> receieved click
// nothing happens!


Hanging events via attach methods

This method is not cross-browser, but it has one great advantage - multiple event handlers can be hanged on one event. To make it cross-broser you can use the following example:

myAttachEvent = function	(object, event, handler){
//.... 
// Detect user agent someway...
//.... 
	if (isIE )
		object.attachEvent('on' + event, handler);
	else{
		object.addEventListener(event, handler, false);
	}
}
 
myAttachEvent(node, 'click', function(){alert(1)});
myAttachEvent(node, 'click', function(){alert(2)});
// -> recieved click
// '1'
// '2'

The order in wich handlers are run is not defined: it is browser-specific

Closures and events

Situation: you need to make a list of DIVs. Each div must do something with its position as argument:

for(var i=0;IDs[i];i++){
	var div = document.createElement('div');
	div.onclick = function(){ alert(IDs[i])};
	document.body.appendChild(div);
}

It seems that when each div is clicked an alert with different data is shown. E.g. when we click on the first one - alert(IDs[0]) is evaled, second - alert(IDs[1]) and so on. But when you actually do so you see that all alerts are the same! That happened because IDs[i] has been changed each time in the cycle. This IDs[i] is just a reference to data in memory. JavaScript tries to save computer resources by using references. The same applies to arrays and objects.

In PHP

$a = array(1,2,3,4,5,6,7,8,9,10);
$b = $a;
array_shift($a);
print_r($a);
print_r($b);
$a :: Array
(
    [0] => 2
    [1] => 3
    [2] => 4
    [3] => 5
    [4] => 6
    [5] => 7
    [6] => 8
    [7] => 9
    [8] => 10
)
$b :: Array
(
    [0] => 1
    [1] => 2
    [2] => 3
    [3] => 4
    [4] => 5
    [5] => 6
    [6] => 7
    [7] => 8
    [8] => 9
    [9] => 10
)

In JavaScript:

var a = [1,2,3,4,5,6,7,8,9,10];
var b = a;
a.shift();
alert(a+' :: '+b);

will be '2,3,4,5,6,7,8,9,10 :: 2,3,4,5,6,7,8,9,10'; So, the arrays in PHP are copied when evaluating, and arrays in JS are referenced when evaluating

Dirty trick to solve

One of the ways to solve this is setting attributes. They are copied to DOM tree each time when setAttribute() called. Then we access element via this keyword and do all stuff.

for(var i=0;IDs[i];i++){
	var div = document.createElement('div');
	div.setAttribute('position',IDs[i]);
	div.onclick = function(){alert(this.getAttribute('position'))};
	document.body.appendChild(div);
}

Fine. This is also cross-browser. But there are some issues:

  • This is slow. Time consumed to write to DOM tree and read it later
  • You can transfer scalar data, but not objects or arrays

Beautiful trick to solve

Try to understand the code:

var creator = function(num){
	return function(){
		alert(num);
	}
}

Yes, this is function returning function. Remember that functions and variables are the same things for JavaScript, so it makes no difference what to return. Mechanism of this function is:

  1. num is copied to an area in the memory.
  2. It returns function with no parameters but with data of num, which has been copied in the memory

Let's try the example above with some modififcations:

var creator = function(num){
	return function(){
		alert(num);
	}
}
for(var i=0;IDs[i];i++){
	var div = document.createElement('div');
	div.onclick = creator(IDs[i]);
	document.body.appendChild(div);
}

What happens? creator() is called iteratively in the cycle and each time it returns different functions. Exactly what we need!

Making JavaScript fast

All applications with more than 500 lines of code make their creators think about speed issues

In JavaScript the main bottlenecks are:

  1. DOM operations
  2. eval() code
  3. Excessive quantity of event listeners

DOM

DOM realisation in most browsers is extremely slow. There are some workarounds:

  1. Use innerHTML, when it's possible

If you don't need hanging events, don't need access to DOM tree/nodes use innerHTML. Though it is not recommended by W3C, it is cross-browser.

  1. Try to minimize variables usage

Many browsers (IE and Opera) speeds up to 100% when the quantity of intermediate variables minimized

eval() code

Many coders use eval() to access custom property/method of an object:

var callMethod = function(name){
  return eval('MyObject.'+name+'.()');
}
var callProp = function(prop){
  return eval('MyObject.'+prop+);
}

This is not the best way: eval() is very slow and hard to debug. Use square brackets to access needed properties:

var callMethod = function(name){
  return MyObject[name]();
}
var callProp = function(prop){
  return MyObject[prop];
}

This is much shorter and faster.

Events

Try to minimize usage of attach methods. Their multiple usage causes browser to register one more instance of expensive event handler.

Minimize the logic of your event handler. If your event handler is browser-specific never try to detect browser agent in handler, use function returning function once to create your handler.

Hiding slow code

In any way, computer is much faster than human. User doesn't see bits and bytes, he sees a picture on display and reaction of applcation on mouse and keyboard.

Take in mind reaction delays of your application. Move the accents to fast user interfaces. If you need to do something and you know that this "something" takes a lot of time, think how to do this without user attention. Good ways are

  • caching
  • doing such things when user activity is comparatively low

Nothing prevents you from combining both variants

Personal tools