Javascript Tutorials : Language Overview
Contents |
Reserved Words
-
break— looping -
else— logic -
new— objects -
var— variables/attributes -
case— logic -
finally— exception handling -
return— functions -
void— functions -
catch— exception handling -
for— looping -
switch— logic -
while— looping -
continue— looping -
function— functions -
this— objects -
with— ??? -
default— logic -
if— logic -
throw— exception handling -
delete— can't recall the context here -
in— seen in iterations/loops -
try— exception handling -
do— looping -
instanceof— objects -
typeof— objects
Types
- Number
- String
- Boolean
- Object
- Function
- Array
- Date
- RegExp
- Null
- Undefined
Logic
Loops
For
for var i = 0; i < a.length; i++ ){
// do something with a[i]
}
This can be improved by caching a.length at start:
for var i = 0; j = a.length; i < j; i++ ){
// do something with a[i]
}
Objects
Basic Object Creation
var obj = new Object();
Is equivalent to:
var obj = {}; //object literal syntax
Property Access
obj.name = "Chad"; var name = obj.name;
Is equivalent to:
obj["name"] = "Chad"; var name = obj["name"];
Object literal syntax (AKA JSON)
var obj = {
name: "Carrot",
"for": "Max",
details: {
color: "orange",
size: 12
}
}
with reference looking something like:
obj.details.color
or as we've seen above, the equivalent:
obj["details"]["size"]
Iterating over keys and attributes
var obj = { 'name': "Chad", 'age': 26 };
for( var attr in obj){
print( attr + ' = ' + obj[attr]);
}
Arrays
The safest way to append to an array is demonstrated below:
var animals = ["dog", "cat"]; animals[animals.length] = "hen";
Array Methods
-
animals.toString() -
animals.toLocaleString() -
animals.concat(item,..) -
animals.join(sep) -
animals.pop() -
animals.push(item,..) -
animals.reverse() -
animals.shift() -
animals.splice(start,end) -
animals.soft(compFunction) -
animals.splice(start,delcount,[item]..) -
animals.unshift([item]..)
Functions
function add(x,y){
var total = x + y;
return total;
}
However, the better implementation av the above function would use the arguments object.
function add(){
var sum = 0;
for var i = 0; j = arguments.length; i < j, i++){
sum += arguments[i];
}
return sum;
}
What if our numbers we're summing are already contained in an array? Do we have to rewrite our function? No.
add.apply(null, [2,3,4,5,6]);
Functions are objects with methods too! The apply method takes an array of arguments as the second argument.
The following is a semantically equivalent to our earlier add() function:
var add = function(){
var sum = 0;
for var i = 0; j = arguments.length; i < j, i++){
sum += arguments[i];
}
return sum;
}
The block scope trick
Block scope is a feature of C where every set of braces defines a new scope. It can be simulated in JavaScript.
var a = 1;
var b = 2;
(function(){
var b = 3;
a += b;
})();
The results:
> a 4 > b 2
Recursive Functions
function countChars(elm) {
if(elm.nodeType == 3){ //TEXT_NODE
return elm.nodeValue.length;
}
var count = 0;
for (var i = 0, child; child = elm.childNodes[i]; i++){
count += countChars(child);
}
return count;
}
Using arguments.callee now:
var charsInBody = (function(elm) {
if(elm.nodeType == 3){ //TEXT_NODE
return elm.nodeValue.length;
}
var count = 0;
for (var i = 0, child; child = elm.childNodes[i]; i++){
count += argumente.callee(child);
}
return count;
})(document.body);
This function remembers how many times is has been called:
function counter(){
if( !arguments.callee.count ){
arguments.callee.count = 0;
}
return arguments.callee.count++;
}
Sampe usage:
> counter(); 0 > counter(); 1
Constructors
function Person(first,last){
return {
first: first,
last: last,
fullName: function(){
return this.first + ' ' + this.last;
}
}
}
Now let's use it:
var p1 = new Person("Chad","Lindstrom");
p1.fullName();
As you can expect, this should output Chad Lindstrom.
JavaScript is an ambidextrous language, thus, allowing you to do things more than one way. The above constructor can also be done using the following:
function Person(first,last){
this.first = first;
this.last = last;
this.fullName = function(){
return this.first + " " + this.last;
}
}
Sharing Methods
function Person(first,last){
this.first = first;
this.last = last;
this.fullName = personFullName;
}
function personFullName(){
return this.first + " " + this.last;
}
Or of course, the infamous 'prototype'
function Person(first,last){
this.first = first;
this.last = last;
}
Person.prototype.fullName = function(){
return this.first + " " + this.last;
}
instanceof
> var a = [1,2,3]; > a instanceof Array true > a instanceof Object true > a instanceof String false
Inheritance
> s = new Person("Chad","Lindstrom");
> s.firstNameCaps();
TypeError on line 1: s.firstNameCaps() is not a function
> Person.prototype.firstNameCaps = function():
return this.first.toUpperCase();
}
> s.firstNameCaps();
CHAD
Now for the inheritance:
> var s = "Chad";
> s.reversed();
TypeError on line 1: s.reveresed() is not a function
> String.prototype.reversed = function():
var r = ;
for(var i = this.length - 1; i >= 0; i--){
r += this[i];
}
return r;
}
> s.reversed();
dahC
> "This can now be reversed".reversed()
desrever eb won nac sihT
Example
function Geek(){
Person.apply(this,arguments);
this.geekLevel = 5;
}
Geek.prototype = new Person();
Geek.prototype.setLevel = function(lvl){
this.geekLevel = lvl;
}
Geek.prototype.getLevel = function(){
return this.geekLevel;
}
new Person()?
- We're using an instance of the Person object as out prototype
- We have todo this, because we need to be able to modify out prototype to add new methods that are only available to Geek instances
- This is counter-intuitive and, well, a bit dumb
Inheritance Solutions
- design classes with inheritance in mind - don't do anything important in the constructur (that might break if you create an empty instance for use as a prototype)
- use one of the many workarounds
- Prototype's Class.create()
- The stuff you get by searching for "javascript inheritance" on the Web
Advanced Functions
- a function is just another object
- you can store it in a variable
- you can pass it to another function
- you can return if from a function
Some Examples
ArrayMap
function arrayMap(array,func){
var result = [];
for(var i = 0; i < array.length; i++){
result[i] = func(array[i]);
}
return result;
}
function calcVat(price){
return price * 1.175;
}
var prices = [10,8,9.50];
pricesVat = arrayMap(prices,calcVat);
Sales Tax Factory
function salesTaxFactory(percent){
function func(price) {
return price + (percent/100) * price;
}
return func;
}
calcVat = salesTaxFactory(17.5);
calc4 = salesTaxFactory(4);
pricesVat = arrayMap(prices,calcVat);
prices4 = arrayMap(prices,calc4);
Operation Factory
function makeOp(op,y){
switch(op){
case '+':
return function(x){ return x + y };
case '-':
return function(x){ return x - y };
case '/':
return function(x){ return x / y };
case '*':
return function(x){ return x * y };
default:
return function(x){ return x };
}
}
var third = makeOp('/',3);
var dbl = makeOp('*',2);
print(third(24));
print(dbl(5));
Closures
- The code above is an example of closures in action.
- A closure is a function that has captures the scope in which it was defined
- Actually, functions in JavaScript have a scope chain (similar to the prototype chain)
Singleton
- JavaScript shares a single global namespace
- It's easy to clobber other people's functions and variables and easy for others to clobber yours
- The less code affecting the global namespace the better
var chad = (function() {
var myVar = 5; //private
function init(x){
//can access myVar and doPrivate
}
function doPrivate(x){
// ... invisible to the outside world
}
function doSomething(x,y){
// can access myVar and doPrivate
}
return {
'init':init,
'doSomething':doSomething
}
})();
chad.init(x);
Singleton Benefits
- lets you wrap up a complex application with doznds of functions up in a single, private namespace - a closure.
- this lets you expose only the functions that make up your applications external interface
Memory Leaks
- to understand memory leaks, you need to understand a bit about garbage collection
- Stuff gets freed up automatically when it's no londer in use (both JavaScript objects and jost objects, such as DOM nodes)
- IE uses different garbage collectors for JS and for the DOM, and can't handle circular references between them
This leaks:
function leak() {
var div = document.getElementById('d');
div.obj = {
'leak': div
}
}
This also leaks:
function sneakyLeak() {
var div = document.getElementById('d');
div.onclick = function(){
alert("hi!");
}
}
The solution:
function sneakyLeak() {
var div = document.getElementById('d');
div.onclick = function(){
alert("hi!");
}
div = null;
}
Performance
De-reference complex lookups
var s = document.getElementById('d').style;
s.width = '100%';
s.color = 'red';
// ...
s.display = 'block';
... especially inside loops
var lookup = foo.bar.bav;
for(var i = 0; i < 1000; i++){
lookup.counter += someCalc();
}
Suggested Libraries
- Dojo Toolkit — http://dojotoolkit.org
- Yahoo UI Library — http://developer.yahoo.net/yui/
- Mochikit — http://mochikit.com
- Prototype — http://prototype.conio.net
- Script.aculo.us — http://script.aculo.us
- jQuery — [1]
References
- http://simon.incutio.com/slides/2006/etech/javascript/js-tutorial.001.html — Currently nearly all of the content for this turorial has been stripped from Simon's presentation. His presentation was bitmap based, and thus not searchable or easily scanned.
- Doh! I just found Simon's HTML and PDF version
This page has been accessed 2,309 times. This page was last modified 18:47, 9 March 2007.