Blog of Jeff A blog about programming and random other things.

26Oct/09link

“Brief” Guide to JavaScript – Part 10

Yes, this is no longer becoming brief; so check out the growing list of previous parts:

Objects Revisited

Objects are the core of JavaScript, so I'm going to a bit further in-depth than previously mentioned. I didn't say explicitly, but everything is JavaScript is an object, booleans, strings, numbers, arrays, functions, etc. are all objects. Before we talk further, I want to quickly review some terminology of objects:


myobj = {}; // constructor that creates an object;             // In this case, an empty object.
myobj.property; // accessing a property
myobj.method(); // calling a function which belongs to an object, aka a method.
// we can also access properties, methods, and references using the// array-styled notation
myobj['property']; // 'property' is called a key
myobj['method'](); // 'method' is the key
myobj['anotherobj']; // 'anotherobj' is the key

References

In contrast to what I initially explain, variables store references to objects. This is slightly different than simply storing data. I feel diagrams explain this the best. Say we do something like this:


var myobj = {'hello': 'world'};
var myobj2 = myobj;

JavaScript engines store the data similar to this:

This means if we change our object, the changes are visible through other variables:


myobj.hello = 'jk';
alert(myobj2.hello); // displays 'jk'

To truly copy an object, we have to manually copy every property:


var myobj2 = {};
for(var p in myobj){
    myobj[p] = myobj[p];
}

This assumes that all the properties don't contain their own properties (like an array). Changing the property or variable changes where that property/variable points to. So:


var myvar = true;
var myvar2 = myobj;
myvar = false;

Which produces something like this:

In simplest terms, you can change where the variable points to, but setting one equal to another will share the same data source. This behavior also apply to function parameters. The rule of thumb is: for objects (those you use {}), arrays, and anything created with a new keyword behave as references.

Reflection Basics

Reflection is a programming terminology which a program that is aware of itself (not in the skynet terms): knowing the existence of variables, functions, or properties. This is particularly easy in JavaScript due to array-styled notation:


var css = ['borderColor', 'backgroundColor'];
var el = document.getElementById('header');
for(var style in css){
    el.styles[style] = 'transparent'; // remove colors.
}

A bit more practical example is when creating similar functions:


var names = {
    'Height': 'height',
    'Width': 'width',
    'Bgcolor': 'backgroundColor',
    'Color': 'color',
    'Size': 'fontSize'
};

for(var fnName in names){
    (function(n){
    window['set'+n] = function(element, value){
        element.styles[names[n]] = value;
    };
    })(fnName);
}
// test it
setColor(document.getElementById('header'), 'red');

As you can see, we can use variables outside our anonymous functions, but you have to beware when the variable is updated in a loop. This is because the function will use the value of the variable at the time of the function call. So after the for loop finished, fnName will be 'Size' and all our functions would be change the 'fontSize' element.

To quickly resolve this, we simply create an anonymous function that accepts the fnName variable. With function calls, non-referenced variables are duplicated (remember: arrays, objects, or things using new are references), so we can use that variable when it was during the function declaration, inside the loop.

This outer scoping of variables is called dynamic scoping, where the values are based on when you call the functions, not when the function was defined.

Classes

Once you start writing larger and larger JavaScript-based applications, you'll may opt to use a more Object-Oriented approach. Classes help provide a "blackbox" approach to stateful widgets/systems. I'm not going to write a lengthy discussing the pros & cons, arguing isn’t my cup of tea ;)

If you haven't used classes much, I'll quickly review some terminology:

  • Property: A variable "about” the object. Think of a characteristic/trait of a particular object: like the box’s color – color would be the property. Identical to properties in object definitions.
  • Method: A name for functions that belongs to a class. Other words, properties that are functions.
  • Class: A "blueprint." Classes define properties and methods. For example: a class would be the architecture's design for a house.
  • Instance: A representation of the "blueprint". Instances can have different values for properties. Continuing our example: An instance would be an actual house. One instance could be blue (property color = blue) and another instance could be red.
  • Static: Treats the class almost like a namespace. Static properties and methods can be access directly. Unlike regular properties and methods, the static variants can't access the currently operating instance because they don't exist in an instance.

Since JavaScript is a bit unusual for classes, which we'll cover shortly.

Instantiated Classes

So we need to define some classes before we create instances of them. JavaScript classes can be created via functions:


function Person(){
}

Seems like a useless function definition, but this is our bare-minimal class definition! We can instantiate the almost useless class:

var john = new Person;

If you've used Object-Oriented programming in other languages, this is absolutely useless. But in JavaScript, properties can be created after the class has been instantiated.

john.name = "John Doe"; // works.

Why? Class instantiations are identical to creating objects. See these:


var myobj = {};
var myobj2 = new Object; // identical
var myobj3 = new Person; // our class is the same

Although you should use the former over the other alternatives. To make our class a bit better before, let's redefine our person class:


function Person(name, phone){
    this.name = name;
    this.phone = phone;
}
var john = new Person('john doe', '123 456 7890');
alert(john.name);
alert(john.phone);

Here we utilize our handy this variable which allows us to set properties and methods which we can access when we instantiate the class. The function parameters act as a constructor, which provides some values we can use when instantiating a class.

Of course we can make it more complex; let's add a method:


function Person(name, phone){
    this.name = name;
    this.phone = phone;
    this.shout = function(){
        alert('hello! My name is ' + name);
    }
}
var john = new Person('john doe', '123 456 7890');
john.shout(); // alerts ‘hello! My name is john doe’

Just like any JavaScript object, just easier to replicate using instances.

Static Classes

Unlike instances, static classes don't require instantiation. Static classes are basically single-instanced classes. The easiest way is to simply define them like namespaces (see previously). But if you want a class to have both static and dynamic properties, simply create the dynamic first:


function Person(name, phone){
    // dynamic-class code
    this.name = name;
    this.phone = phone;
    Person.count++; // modifying our static property
}
Person.count = 0; // static property

Why does this work? Because everything are objects in JavaScript, including functions.

Prototypes

If you haven't noticed, there's one problem with the whole instantiated thing see:


function Person(){}
var john = new Person;
john.walkSpeed = 100;

If we wanted all person instances to have the walkSpeed property, we would need to add that property to all instantiated person classes. Not cool. To resolve this, we can use the special property in all objects: prototype. This allows us to assign properties to all instances of our class.


function Person(){}
var john = new Person;
Person.prototype.walkSpeed = 100;
alert(john.walkSpeed); // prints 100
var joe = new Person;
alert(joe.walkSpeed); // prints 100
john.walkSpeed = 10; // only affects john, poor fellow.

Using prototypes, we can implement like traditional object oriented inheritance.


function Person(){ }
function Employee() {}
Employee.prototype = new Person();

If you are observant, you'll notice we have a restriction: the constructor has to have no parameters. Unfortunately, achieving good prototype-based inheritance with constructor-supported inheritance is a tougher problem (out of scope of this article). I'll direct you here for a do-it-yourself implementation or JavaScript frameworks: prototype & mootools are good OO frameworks.


This wraps up this lengthy week. Next up is the trendy AJAX stuff. Oh boy!

  • Share/Bookmark
blog comments powered by Disqus

Recent Posts

Topics

Archives

Following

Links