Better JavaScript

Better JavaScript - Introduction

Writing Better JavaScript for Java developers.

As we demand a richer web user interface, >>JavaScript becomes a more important programming language. You may have heard the name >>AJAX used to refer to dynamic web applications, or maybe >>Web 2.0.

Java developers are expected to know DHTML and JavaScript along with the slew of enterprise technologies such as JDBC and JMS.

Most of us learn via 'Search and Play' - we find something similar, via Google, to what we need and play with it until it does exactly what we want. There may not be a lot of thought that goes in to the solution, since at that point, it works. It's only later that we come back and look at what we've done, sometimes in horror :-)

So our first pieces of JavaScript are usually copy/pasted functions from sites such as >>JavaScript Source , >>JavaScript About, >>DynamicDrive or >>w3schools.

If you're lucky, you'll find sites like Douglas Crockford's.

So do your scripts and js files look like this?

var x;
var sumOfItems
var currentItem;

function openWindow(pwURL,pwName) { … … … }

function calculateTotals(formName, fieldPrefix) { … … … }

Are they are bunch of seemingly unrelated functions with some variables declared on the page? Do you have scripts included that 'clash' with other scripts by declaring the same variables or functions? Are you writing most of your other code in an Object Oriented language and wish that JavaScript was better than this?

Well, there is something you can do about it. As Douglas Crockford puts it, JavaScript is >>The World's Most Misunderstood Programming Language. Sometimes all you need is a simple function, but there are times when you want to write reusable code.

Next we'll look at JavaScript from a Java Programmer's mindset: objects in JavaScript, writing your own objects in javascript, constructors, public and private methods and variables, static vs instance methods and variables. This wont be a JavaScript reference, there are already plenty of those available on the web, rather it's a look at some of JavaScript's features from a Java Developer's perspective.

Articles in this series: >>Objects
>>Functions
>>Constructors
>>Methods
>> The prototype property

Better JavaScript - Objects

JavaScript has several built-in types, for example: Array, Boolean, Date, Function, Math, Number, RegExp and String.

You create instances of these (and all objects) using the new operator:

var friends = new Array();
friends[0] = "Me";
friends[1] = "You";
// or using an Array literal
var otherFriends = ["Steve", "Pete"];

Objects in JavaScript are simply a collection of properties, similar to a Map in Java. And in more recent versions of JavaScript, you can also define them with a literal expression, e.g:

var goodCar = {make: "Subaru", model: "Forester", year: 2005};
which is equivalent to:
var goodCar = new Object();
goodCar.make = "Subaru";
goodCar.model = "Forester";
goodCar.year = 2005;
Properties of an object can be accessed using their literal names or square brackets:
// same as goodCar.make = "Holden";
goodCar["make"] = "Holden";

This can be very useful if a property clashes with the name of a variable.

Note that properties can hold primitive values (2005), or objects like Arrays, Dates and even Functions, e.g.:

function CarToString() {
  return this.make + " " + this.model + " (" + this.year + ")";
}
goodCar.toString = CarToString;
alert(goodCar.toString());

Properties can be added to an object at any time. This is very different to Java where methods and fields of an object are defined by the class at compile time.

Better JavaScript - Functions

Note that Function is a built-in type. Usually you create Functions by declaring them:

function add(number1, number2)
{
    return number1 + number2;
}
var total = add(12,25);
But you could also use the new operator:
// note capital F
// last argument is the source of the function.
// The first ones are the arguments to the function being created.
var sum = new Function("number1", "number2", "return number1 + number2;");
var total = sum(12,25);
Or with no name:
var adder = function(number1, number2)
{
    return number1 + number2;
}

var total = adder(12,25);

In these examples add, sum and adder are global variables that reference Function objects

Scope for variables is similar to that of Java; if a variable is declared inside a function, it's only accessible from within the function. If a variable is declared outside of all functions, it is a global variable available to all others.

Functions can also be nested inside other functions, e.g. :

function calculateTax(value)
{
  function taxRate()
  {
    return 0.1;
  }
  return value + (value * taxRate());
}

In the above example, the function taxRate is local to the calculateTax, i.e. it is not visible outside calculateTax.

Better JavaScript - Constructors

There is no class statement in JavaScript. JavaScript does not use classes to create new Objects.

To create an object in JavaScript, use the new operator and a function.

function Car(make, model, year)
{
  this.make = make;
  this.model = model;
  this.year = year;
  this.toString = function() {
    return this.make + " " + this.model + " (" + this.year + ")";
  }
}
var myCar = new Car("Subaru", "Forester", 2003);
alert("My car was made in "+ myCar.year);

You'll notice that JavaScript is a dynamically typed language, you don't need to declare types for the variables you are going to use. It also means that if you expect data to be of a certain type (like year above), then you will need to check it yourself.

In the above example, the construction (aka the Car function) used the parameters model, make and year and created properties for them in the current object by using the special variable, this. The properties can be accessed later using the dot notation as above (myCar.year), or using square brackets (myCar'year')

Any object created using the Car constructor above will have properties: make, __model__, year and toString. In Java these would be public members.

Since a constructors is just a function, you can take advantage of all the usual features of a function, in a constructor, e.g. local variables and nested functions. In the above example, the toString function is defined within the constructor, and made available as a property. toString is a method of the myCar object.

Once you've created an object, JavaScript automatically set it's constructor property to the function used to create the object, i.e.

myCar.constructor == Car
would be true;

Better JavaScript - Methods

Methods are simply JavaScript functions that are available on an object. Typically methods use properties of the object to perform their work. In the Car constructor example:

function Car(make, model, year)
{
  // other stuff removed
  this.toString = function() {
    return this.make + " " + this.model + " (" + this.year + ")";
  }
}

a property called toString is added to the instance being initialised. The property is a function which returns a string based on the make, model and year properties of the current object.

Methods can be added to an object at any time, not only during the constructor, e.g.

// see previous creation of myCar object in Constructors
myCar.isOld() = function()
{
  return (new Date().getFullYear - this.year) > 5;
}

This gives us a new method on myCar which tells us if the car is more than 5 years old.

Usually, you wont want to add a method to a single object, you want the methods available for all objects of that type, and define the method in the constructor, or the prototype, which we'll be covering in the next article.

Methods can use any of the objects properties via the special variable, this. They can also use parameters passed to the method, anything defined in the same scope, and global variables. So the toString method in our example can also use the parameters passed to the Car constructor, since they are defined in the same scope, as well as any local variables of the Car constructor.

This often creates confusion in people that are new to JavaScript. Let's look at a common error:

function Car(make, model, year)
{
  this.make = make;
  this.model = model;
  this.year = year;
  this.toString = function() {
    // wrong: returns a string from values passed in from the constructor!
    return make + " " + model + " (" + year + ")";
  }
}
var myCar = new Car("Holden", "SS Ute", 2005);
alert(myCar.toString());
myCar.make="Calais";
alert(myCar.toString());

The first alert shows "Holden SS Ute (2005)", and so does the second whereas you would expect it to show "Holden Calais (2005)". The toString function is using the make, __model__ and year arguments of the constructor and building a string from them.

If we later change any of those properties from the value passed into the constructor, the toString method will produce the wrong results.

Better JavaScript - The prototype property

JavaScript doesn't have a class statement that statically defines the methods and variables for a given object, so when you try to use a property of an object in JavaScript, the language has a specific order it uses to determine if that property exists.

For example:

function Car(make, model, year)
{
  this.make = make;
  this.model = model;
  this.year = year;
  this.toString = function() {
    return this.make + " " + this.model + " (" + this.year + ")";
  }
}
var myCar = new Car("Subaru", "Forester", 2003);
var rating = myCar.fuelRating;

In the last line, we've asked JavaScript for the fuelRating property of myCar.

  1. JavaScript will first look at myCar, and try to find a property there.
2. If it can't find it on the given object, it will check if the object has a prototype property. (This is called the prototype chain). 3. If the object has a prototype property, Goto Step 2, using the prototype property as the object to search.

i.e. it searches for: myCar.fuelRating, myCar.prototype.fuelRating, myCar.prototype.prototype.fuelRating etc.

This continues until the property is found on the prototype chain, or the prototype property doesn't exist.

The prototype property of a constructor holds defaults that are available for all objects created with that constructor. This is similar to what a class does in Java.

Remember, as I mentioned in Objects that you can add properties to objects at any time.

This means that you can add properties to an object's prototype at any time, and from there on in, the object will behave as if the property was defined in the constructor.

This can be very handy if, for example, you want to make sure every Element in your document has a hide() and show() method available:

Element.prototype.hide = function()
{
  this.style.display = "none";
}
Element.prototype.show = function()
{
  this.style.display = "";
}
and in your document, you can use:
<p>
Hello there. Click this:
<input type="button" value="Click me" onclick="document.getElementById('fred').hide();"/>
</p>
<p id="fred">Text to be hidden</p>

This means that if you don't like the functionality provided by the browser for a given class, like Element, you can write your own methods and add them in.

As you might be able to guess, the prototype property is very important for inheritance in OO programming with JavaScript.

(摘引至 >>dIon Gillard)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章