OOP in JavaScript - Part 2: Static classes and Singleton

Permanent Link: OOP in JavaScript - Part 2: Static classes and Singleton 15. September 2009 Comment Comments (4)

After I've covered normal classes in Part 1 of the series, the second part will focus on static classes and singletons. As before basic OOP and JavaScript knowledge is needed.

Generally writing and using static classes is monstly the same as normal classes. The difference is that you don't need to instantiate the object with new and you can't use prototyping nor this, since everything is in static context. One useful implementation for static classes is the Registry Design Pattern. First off we create the class with a property to store the registry values in afterwards:

function Registry()
{
}

Registry._data = {};

Right now, I can't really do a lot with this class, that's why I'll create a static method that allows me to set key-value-combinations:

Registry.set = function(key, value) {
Registry._data[key] = value;
}

Now I'm able to register stuff in the registry. Since I don't need an instance of the class I can call my method directly:

Registry.set('userIsAuthorized', false);

I'll leave out the getter you'd still need for a useful registry.

If you want to prevent anyone from writing new Registry() you only have to throw an exception in the constructor:

function Registry()
{
throw('You cannot instantiate Registry');
}

Maybe for some reason you wanna use Registry as a singleton. In that case you have to combine normal class methods and properties with static ones. You write the Registry as a normal class and implement one static property instance and one static method getInstance. The Registry class would then look like this:

function Registry()
{
}

Registry.instance = null;

Registry.getInstance = function() {
if (Registry.instance === null) {
Registry.instance = new Registry();
}
return Registry.instance;
}

Registry.prototype._data = {};

Registry.prototype.set = function(key, value) {
this._data[key] = value;
}

Since JavaScript doesn't have access modifiers like private, public or protected I had to remove the exception from the constructor. You could do it with a randomly generated token passed to the constructor, but this method is not bulletproof like any other I can think of.

In part 3 (that'll come later this week) I will write about extending classes.

OOP in JavaScript - Part 1: Writing classes

Permanent Link: OOP in JavaScript - Part 1: Writing classes 12. September 2009 Comment Comments (5)

OOP in JavaScript works a bit different than known from other languages. That's why I decided to do a series of "OOP in JavaScript" blogposts, where I want to show how OOP in JavaScript works. The series will discuss topics like creating classes, prototyping, extending classes, static classes, scoping, and so on. To understand these postings a basic knowledge of JavaScript and OOP is needed. This first part is about creating classes/prototyping.

First thing you need to know: There is now keyword class in JavaScript. In order to create a class in JavaScript, all you have to do is to create a function and then create a new class instance by using the known keyword new:

function Product() {}

var product = new Product();

The function we've created is the constructor of our new class. To create methods and properties there are two ways: You can either declare them in the constructor or you can do prototyping.

Declaring it in the constructor:

function Product() {
this.id = 71288;

this.getId = function() {
return this.id;
}
}

Prototyping:

function Product() {}

Product.prototype.id = 71288;

Product.prototype.getId = function() {
return this.id;
}

Personally I prefer prototyping as it is more clear. If you want to call the function getId() it always works the same way with both methods:

var product = new Product();
alert(product.getId());

This class is still quite static, since the id is hardcoded in it. To make it dynamic I just need to modify the constructor to make it accept a config object. Notice that I replaced the id property with a config property that stores the whole config given to the object.

function Product(config) {
this.parseConfig(config);
}

Product.prototype.config = {};

Product.prototype.parseConfig = function(config) {
if (typeof config != 'object') {
throw('Parameter "config" must be of type object');
}
// ID should always be set and a number
if (typeof config.id != 'number') {
throw('Config Parameter config.id must be a number');
}
this.config = config;
}

Product.prototype.getId = function() {
return this.config.id;
}

As you can see I also already implemented checks that the config must always be an object and that an id must always be set and a number. Creating a new instance of the class now looks like this:

var product = new Product({
id: 71288
});

This way we can now dynamically create Product Objects based on Product IDs we read from e.g. a database.

In the second part, that will come within the next few days I will write about static classes.

Haystack-Needle-Sheet

Permanent Link: Haystack-Needle-Sheet 4. August 2009 Comment Comments (4)

Surely every PHP developer has come across the PHP Haystack-Needle-Phenomenon: Mostly the parameter order is $haystack, $needle but in some cases it's $needle, $haystack for no apparent reason. Trying to find regularities I found out that it's only the array functions that use needle, haystack instead of haystack, needle - assuming I didn't forget any functions. For that reason I created a Haystack-Needle-Sheet, which shows you which function uses haystack, needle and which one needle, haystack.

If you should come across functions that are missing on this list, please let me know.

You can download the Haystack-Needle-Sheet here

Cookies in JavaScript

Permanent Link: Cookies in JavaScript 29. Juli 2009 Comment No Comment

Using in Cookies is rather complicated. All the cookies are in the string document.cookie. Here's a little static class I wrote a while ago to handle saving, reading and removing Cookies in JavaScript

/**
* Static Class for Cookie functions
*/
function Cookie()
{
}

/**
* Save new Cookie
*
* @param string name
* @param string value
* @param number days
*/
Cookie.save = function(name, value, days)
{
if (typeof days != 'undefined') {
var date = new Date();
date.setTime(date.getTime() + (days*24*60*60*1000));
var expires = "; expires=" + date.toGMTString();
} else {
var expires = "";
}
document.cookie = name + "=" + value + expires + "; path=/";
}

/**
* Read Cookie value
*
* @param string name
*/
Cookie.get = function(name) {
var nameEQ = name + "=";
var ca = document.cookie.split(';');
for(var i=0;i < ca.length;i++) {
var c = ca[i];
while (c.charAt(0)==' ') {
c = c.substring(1,c.length);
}
if (c.indexOf(nameEQ) == 0) {
return c.substring(nameEQ.length,c.length);
}
}
return null;
}

/**
* Delete Cookie
*
* @param string name
*/
Cookie.remove = function(name) {
Cookie.save(name,"",-1);
}

DNS Cache 1.5 released

Permanent Link: DNS Cache 1.5 released 13. Juli 2009 Comment Comments (3)

Today the latest version 1.5 of my Firefox plugin "DNS Cache" finally went public. Apart from Firefox 3.5 compatibility the following things have changed:

  • Explicitly flush DNS cache when deactivating
  • Toolbar Icon now has a context menu (right click): "Enable / Disable DNS Cache" and new:
  • "Flush DNS Cache": Flushes the DNS Cache no matter if the cache is disabled or not
  • Toolbar Icon now has to be double clicked in order to change the dns cache state

You can get the Firefox addon at the Firefox Add-ons page. If you've already installed it from there you should get the update automatically.

If you should experience any problems, please let me know!

MySQL: Pagination - SQL_CALC_FOUND_ROWS vs COUNT()-Query

Permanent Link: MySQL: Pagination - SQL_CALC_FOUND_ROWS vs COUNT()-Query 17. Juni 2009 Comment Comments (10)

When using pagination for let's say a list of offers that where never clicked, you have to know the exact amount of offers (which were never clicked) in order to know how many pages you have. Now there are 2 possible ways of calculating the exact amount of offers: You can use either SQL_CALC_FOUND_ROWS or you can setup a second query with a COUNT() in it. I did the tests with SQL_NO_CACHE in order to get the best results possible. The clicks table has about 18.000.000 rows, the offer table about 800.000. Let's start with some time results.

Using SQL_CALC_FOUND_ROWS:

mysql> SELECT SQL_NO_CACHE SQL_CALC_FOUND_ROWS o.offer_id
-> FROM offer AS o
-> LEFT JOIN clicks AS c
-> ON (o.offer_id = c.offer_id)
-> WHERE c.offer_id IS NULL
-> LIMIT 50,50;
50 rows in set (30.84 sec)

mysql> SELECT FOUND_ROWS();
1 row in set (0.00 sec)

Using a second query with COUNT():

mysql> SELECT SQL_NO_CACHE o.offer_id
-> FROM offer AS o
-> LEFT JOIN clicks AS c
-> ON (o.offer_id = c.offer_id)
-> WHERE c.offer_id IS NULL
-> LIMIT 50,50;
50 rows in set (0.03 sec)

mysql> SELECT SQL_NO_CACHE COUNT(o.offer_id)
-> FROM offer AS o
-> LEFT JOIN clicks AS c
-> ON (o.offer_id = c.offer_id)
-> WHERE c.offer_id IS NULL;
1 row in set (30.97 sec)

At a first glance they look equally fast, both taking about 30 seconds. But: They are only equally fast, when query caching is turned off. Let's assume we're on a high-traffic website where performance matters, so we turn the query cache on. MySQL Query caching is like a key-value cache with the key being the EXACT query and the resultset being the value. Once we turn on the cache, the pagination is way faster with the second query using COUNT().

Why?

When using SQL_CALC_FOUND_ROWS the application has to calculate the found rows every single time we turn the page, because the query changes, while the COUNT()-Query always remains the same, meaning that its result comes from the query cache from the second time on. Let's emulate:

Using SQL_CALC_FOUND_ROWS:

mysql> SELECT SQL_CALC_FOUND_ROWS o.offer_id
-> FROM offer AS o
-> LEFT JOIN clicks AS c
-> ON (o.offer_id = c.offer_id)
-> WHERE c.offer_id IS NULL
-> LIMIT 50,50;
50 rows in set (31.13 sec)

mysql> SELECT FOUND_ROWS();
1 row in set (0.00 sec)

mysql> SELECT SQL_CALC_FOUND_ROWS o.offer_id
-> FROM offer AS o
-> LEFT JOIN clicks AS c ON (o.offer_id = c.offer_id)
-> WHERE c.offer_id IS NULL
-> LIMIT 100,50;
50 rows in set (30.71 sec)

mysql> SELECT FOUND_ROWS();
1 row in set (0.00 sec)

Using a second query with COUNT():

mysql> SELECT o.offer_id
-> FROM offer AS o
-> LEFT JOIN clicks AS c
-> ON (o.offer_id = c.offer_id)
-> WHERE c.offer_id IS NULL
-> LIMIT 50,50;
50 rows in set (0.03 sec)

mysql> SELECT COUNT(o.offer_id)
-> FROM offer AS o
-> LEFT JOIN clicks AS c
-> ON (o.offer_id = c.offer_id)
-> WHERE c.offer_id IS NULL;
1 row in set (31.11 sec)

mysql> SELECT o.offer_id
-> FROM offer AS o
-> LEFT JOIN clicks AS c
-> ON (o.offer_id = c.offer_id)
-> WHERE c.offer_id IS NULL
-> LIMIT 100,50;
50 rows in set (0.04 sec)

mysql> SELECT COUNT(o.offer_id)
-> FROM offer AS o
-> LEFT JOIN clicks AS c
-> ON (o.offer_id = c.offer_id)
-> WHERE c.offer_id IS NULL;
1 row in set (0.00 sec)

Et Voilà! While the SQL_CALC_FOUND_ROWS Queries took more than one minute together, the queries with the second COUNT() query only took a bit more than 30 seconds together, meaning they are twice as fast.

I'm pretty sure there are situations where SQL_CALC_FOUND_ROWS is the way to go, but in cases like this one you definately wanna go for the COUNT()-Query.

Canonicals: What they are and how to use them

Permanent Link: Canonicals: What they are and how to use them 10. Juni 2009 Comment One Comment

Today I wanna give a short insight on canonicals. A canonical is a (fairly new) SEO item in the head section of a HTML document, which contains the parent URL. Let's say you have a page which contains a sortable list whose URL is www.chip.de/sortable-list. Besides AJAX-sorting you also have sorting with URLs like www.chip.de/sortable-list/order/price/dir/desc, which reloads the page showing the sortable list ordered by the price descending. Usually you either 2 would have pages in the Google index with the almost the same content or 1 page since you put noindex,nofollow in one of them. This is where canonical comes into play:

First off you leave the noindex, nofollow in the page with the sorted list. Second you put a canonical into the HTML head section telling search engines where it can find the original list!

<link rel="canonical" href="/sortable-list">

That way the sorted list URL will not only not be in the Google index but the original URL gets more "attention".

The latest Firefox versions already show if a canonical is defined:

Canonicals in Firefox

P.S. It does no harm to put the canonical tag in the original page itself.

Scrumfails Part 2

Permanent Link: Scrumfails Part 2 10. Juni 2009 Comment No Comment

Sprint Planning I: The product owner presents an item with 8 storypoints. Not one team member can remember to have ever estimated that item and everyone agrees that it's way bigger than an 8. How the hell could that happen? We don't know. What did we do? We excluded the item from the sprint and set up a meeting to discuss the item.

Job offer at CHIP Online as PHP Developer

Permanent Link: Job offer at CHIP Online as PHP Developer 5. Juni 2009 Comment No Comment

If you speak german and you're looking for a job as PHP Developer, we are looking for one at CHIP Online in the price comparison team.

In case you are interested, click here.

Scrumfails Part 1

Permanent Link: Scrumfails Part 1 4. Juni 2009 Comment No Comment

Estimation meeting. Cards are layed off. One 5, two 8s, one 13. Question from the one with the 5: "Why 8?"

< previous page | next page >