Jumping Into Javascript – Objects and Loops

In the last post I used an array to model a rectangle. This worked for a quick test, however the rectangle is probably best modeled as an object. Especially considering that the rectangle is only part of a candlestick bar that also must include a wick, or line. In this part we’ll turn the rect into an object, then move on to creating a bunch of them and moving them all at the same time using a loop.

The first thing we’ll do is convert rect to be an object. Objects in Javascript are different than objects in many other languages. In many languages objects are class based, the object system in Javascript is prototype based. Very quickly what that means is that, in a class based object system, there is the abstract definition of an object (the class definition) and there are instances of objects defined by the class. In a prototype based system there is no distinction between the two.

In many practical ways these two systems are very similar, however there are some differences that may trip you up. I encourage you to read more about the differences and similarities. Unfortunately I can’t go much more in-depth than that here.

var chart = document.getElementById("chart");
var c = chart.getContext("2d");

chart.onclick = moveRect;

function drawRect() {
  c.fillRect(rect.x,rect.y,rect.width,rect.height);
}

function moveRect() {
  c.clearRect(0, 0, chart.width, chart.height);
  rect.x += 20;
  drawRect();
}

function Rect(x, y, width, height) {
  this.x = x;
  this.y = y;
  this.width = width;
  this.height = height;
}

var rect = new Rect(10, 25, 20, 50);

drawRect(rect)

As you can see we simply use a function to construct a Rect object. The this keyword is similar to self in Python and signifies that the variable is an attribute of the object. To create a new object we have to use the new keyword, this can be seen in the line: var rect = new Rect(10, 25, 20, 50);.

Other than these few modifications, nothing else has changed. rect is still used as a global variable and the functions drawRect and moveRect operate directly on rect. The next thing we’ll do is create a global array where we can store a number of Rects. This will require changing almost everything, however most changes will be minor.

var chart = document.getElementById("chart");
var c = chart.getContext("2d");

chart.onclick = moveRects;

function drawRects() {
  for (var i in rects) {
    var r = rects[i];
    c.fillRect(r.x, r.y, r.width, r.height);
  }
}

function moveRects() {
  for (var i in rects) {
    rects[i].x += 20;
  }
  c.clearRect(0, 0, chart.width, chart.height);
  drawRects();
}

function Rect(x, y, width, height) {
  this.x = x;
  this.y = y;
  this.width = width;
  this.height = height;
}

var rects = [new Rect(10, 25, 20, 50), new Rect(40, 25, 20, 50)];

drawRects();

Make sure that you use the new keyword when you create new objects, even when they are in an array. I spent at least 10 minutes trying to figure out what I was doing wrong in the for loop, just to realize that I did not use the new keyword when I initialized the array!

Also I noticed that, at least some, Javascript implementations are very forgiving regarding errors. Until now I’ve been passing rect as an argument to drawRect in the moveRect function. The drawRect function does not expect any arguments, yet I am allowed to give it one without complaint. I can see this “feature” being problematic down the road, however I can also see that it might be necessary with all the different non-conforming implementations out there. I have since gone back and fixed this in previous posts.

Since we’ve already covered objects and arrays, the only thing new here is the for loop. There are two methods of invoking the for loop in Javascript. The one that I used above is…

for (var i in sequence) { 
  // body;
  // use sequence[i] to access elements
}

One thing to note with this method is that i is not bound to the nth element in sequence, rather i is simply a counter. This method is basically a shorthand for the next method which is more similar to C syntax…

for (var i = 0; i < sequence.length; i++) { 
  // body; 
  // use sequence[i] to access elements
}

This is the standard for loop syntax available in many languages. No matter which method you use you must still use sequence[i] to access the elements. The (var i in sequence) syntax does not act like Python’s for i in sequence.

The next post will explore downloading and manipulating stock data. However I have run into a small problem that I haven’t been able to solve in <30 minutes of searching. It seems that the same origin policy will prevent me from downloading historical data from Google Finance. From what I’m reading I need to find a source of historical quotes that offers the data in JSONP (or CORS) which will allow cross domain access. While I can understand the security implications of allowing arbitrary cross-domain access, this part of the app (which was trivial in Python) is a real pain in Javascript.

GOTO Part 4 – Same Origin Policy, JSONP, XMLHttpRequest, and Cheating with jQuery

Get JamochaTrade on GitHub

 

Links

Introduction to Object-Oriented JavaScript

Advertisements