This is the second part of the JavaScript Quirks for Classical OO Developers. I will cover a bit of the most important things that you may have missed (I certainly did) with JavaScript as a C#/Java Developer without going into too much detail and some references for further reading.
How do I create a class?
In C# and Java, it is simple to think about how you would write a class – it is the blueprint for objects in its purest form – your object is simply an instance of a type (class) that has some methods. In JavaScript, writing a class isn’t quite as obvious, so here are some common patterns used for writing your class.
Before we go into the common patterns though, what is a class in JavaScript? Well, good point, there is no class
in JavaScript. You have a type, function, and object.
A class then in JavaScript is simply a constructor or a function that binds things to this or its prototype or a function that returns an object.
Anonymous Object
Anonymous functions allow the creation of Objects without the need for Constructors. The anonymous Object is most commonly used for passing as arguments – you’ll see this commonly used in jQuery plugins for passing option arguments.
var chuckNorris = {
name : "Chuck Norris",
logName: function() {
console.log(this.name);
}
};
console.log(chuckNorris.logName()); // Chuck Norris
chuckNorris.name = "Bruce Lee";
console.log(chuckNorris.logName()); // Bruce Lee
Revealing Module Pattern
function Person(name)
{
// private
var name = name;
// private function
function MyFunction() {
console.log("hello " + name);
}
// another way of creating private function
var AnotherPrivateFunction = function() {
console.log("hello " + name + " this is AnotherPrivateFunction");
}
// return anonymous objects with functions bound to them
return {
MyFunction: MyFunction
};
}
This is also known as the “Revealing Pattern”. With this pattern, nothing is exposed as public, instead, it returns an anonymous object at the end with everything defined exposed as public. This makes it easy for developers to see what’s available for them to use and this also makes it a bit easier to decide later what needs to be exposed and what needs to remain private without much modification. This approach makes use of the fact that JavaScript keeps the state of variables inside a function, so long as it is referenced somewhere – in this case, it is referenced by the returned anonymous object.
The revealing module pattern keeps track of its state using closure shown in part 1.
The problem with this pattern, when used purely by itself without the use of prototype, is that you are essentially having a copy of each and every single function you define in each instance of your Object – it is highly encouraged to share functions using a prototype.
To demonstrate, see this example:
this
function Person(name) {
this.name = name;
var sayName = function() {
console.log(this.name);
}
this.sayName = sayName;
}
var me = new Person("Andy");
me.sayName() // Andy
This one is a fairly common pattern, simply bind the object to this
to expose for public use – this has the same issue as revealing pattern where you are duplicating a function over and over again for each object created.
Let’s have a look at how using this
looks in the heap.
Notice that this.sayName
for each Object memory reference are different, each one taking up 36 bytes.
Prototype
function Person(name) {
this.name = name;
}
Person.prototype.sayName = function() {
console.log(this.name);
}
This should be your preferred way of adding functions whenever possible as this makes the function shared through the Object’s prototype – it is highly performant and costs less on memory since functions are shared across multiple Objects rather than having a copy of the function for each Object instance.
Remember that an Object’s prototype
is shared among all Objects inheriting from the same prototype
.
Check this example:
function MyType(value) {
this.value = value;
}
MyType.prototype.logValue = function() {
console.log(this.value);
};
var myObj1 = new MyType('world');
myObj1.logValue();
// add new prototype method
MyType.prototype.logValueWithHello = function() {
console.log('hello ' + this.value);
};
var myObj2 = new MyType('larry');
myObj2.logValue();
myObj2.logValueWithHello();
// myObj1 also received a new method
myObj1.logValueWithHello();
Notice that myObj1 also received a new method named logValueWithHello
even though it existed before we added the new method. To truly understand the nature of prototype, check mozilla’s write-up on Inheritance and the prototype chain.
Wow, prototype is cool, that means I can add new functions to pre-existing objects, so that means I can add new functionalities to built-in types like string and array right? Before you think of doing this, think again… It’s usually better to just create a wrapper that adds functions to the object (as what jQuery does) or create a helper/utility function – otherwise, you will have the headache of having to ensure that no name ever clashes with the native methods.
Let’s see how this is referenced in our heap.
Notice that both methods have the same reference.
Further Reading
Addy Osmani’s book – JavaScript Design Patterns
Checking equality
==
Might not be what you expect it to be. ==
operator compares only by value, ===
on the other hand compares both type and value without coercion.
Some examples to illustrate:
1 == "1" // true
1 === "1" // false
0 == "" // true
0 === "" // false
0 == "0" // true
0 === 0 // true
1.0 == 1 // true
// JavaScript only has a single primitive type of numerical values, which is a double precision floating point
1.0 === 1 // true
true == 1 // true
true === 1 // false
false == 0 // true
false === 0 // false
Funnily enough, NaN
doesn’t equal to itself or any value for that matter as the code example below shows.
// all of these return false
NaN == NaN;
NaN === NaN;
NaN == 0;
NaN == false;
NaN == null;
NaN == undefined;
Since NaN is the only type not equal to itself, you could check for NaN
by doing something like this:
function isNaN(x) {
return typeof x === "number" && x != x;
}
Just a fun fact :).
Truthy and falsy
In JavaScript, when you use any value in place of a boolean in an if
statement, they are coerced into boolean value known as truthy or falsy value – so you need to understand what the current’s truthy or falsy value of the type you are using.
Find the truth table for JavaScript here
Other Concepts you need to understand
People to follow
- Douglas Crockford
- Addy Osmani
- Nicholas Zakas
- Paul Irish
- John Resig
Books
- Professional JavaScript for Web Developers – this is quite comprehensive
- Eloquent JavaScript
- Learning JavaScript Design Patterns
- Effective JavaScript
JavaScript is a fun language, it’s easy to get into but difficult to master – have fun !!