Skip to content

Introduction to Javascript

Cédric Warny edited this page Mar 5, 2015 · 11 revisions

Javascript basics

Variables

There are different types of variables.

// This is a comment
var a = 2; // This is a integer
var b = 2.3; // This is a float
var c = "Hello"; // This is a string

Above are the most basic variable types. And then you have more complex structures like arrays and objects.

var arr = ["hello", "world", 1, 4]; // An array is a list of things

Things in arrays are indexed and you can access these things by accessing their index in the array.

console.log(arr[0]); // hello
console.log(arr[1]); // world

An object, like an array, stores things. But instead of accessing the things by their position on an index, we use keys.

var myCar = {
	loc: 11,
	speed: 3
};

// There are two ways to retrieve the things from an object
console.log(myCar.loc); // 11
console.log(myCar["speed"]); // 3

The keys of an object are also known as its properties.

Control flow

The flow of a program is controlled mainly by conditions and loops. Conditions are used to create branches in your code depending the boolean evaluation of a statement: you go one branch if the evaluation is true, the other if false.

if (condition) {
	// Some code
} else {
	// Some other code
}

Examples of evaluations:

var x = 3;
console.log(x === 3); // True
console.log(x < 4); // True
console.log(x > 5); // False

Loops are useful when you need to do the same thing multiple times.

for (var i=0; i<10; i++) {
	// Some code
}

It is very often used to loop through the elements of an array and do something with them.

The syntax for looping through the properties of an object is slightly different:

for (var key in obj) {
	// Some code
}

Functions

Declaring functions can be done in two different ways.

function f() {
	console.log("Hello, world");
};

f(); // Hello, world

var g = function(name) {
	console.log("Hello, " + name);
};

g("John"); // Hello, John 

Function f does not take any input, while g does take name as an input. If you want your function to return some output:

function h(x) {
	return x*2;
}

h(3); // 6

A function also defines a scope. A scope is whatever objects/variables the program interpreter (the machine running your program) is "aware" of at some point while running your program.

var x = 4;

function f() {
	var y = 3;
	console.log(x);
}

f(); // 4
console.log(y); // Error

In the above, the variable x is accessible from within the function f, but the variable y, defined within the scope of f is not accessible in the so-called global scope.

Object-oriented programming in Javascript

A literal object is an object declared manually:

var myCar = {
	loc: 10;
};

myCar.speed = 5; // You can add properties to the object

myCar.loc++; // You can change an object's properties

The line myCar.loc++ is short notation for yourCar.loc = yourCar.loc + 1.

Now, what if there's another car?

var yourCar = {
	loc: 5;
};

yourCar.loc++;

You would have to rewrite the same code for each object. That's not very practical. What if we write a function that will create the objects for us?

var Car = function() {
	var obj = {};
	obj.loc = 10;
	return obj;
};

var myCar = Car();
var yourCar = Car();

The above is a special kind of function, called a constructor, which defines a class. When you call the function, it returns an object, which can be viewed as an instance of the car class. It is good practice to upper-case class names.

The instances of a class returned by a constructor don't just contain properties, but also methods that can modify these properties. See it as the functionality of the object.

var Car = function(loc) {
	var obj = {};
	obj.loc = loc;
	obj.move = function() {
		obj.loc++;
	}
	return obj;
};

The code above is correct but it means that every newly created Car object will store its own move function in memory. That's a waste since the functionality is the same for everybody. While every instance of a car has its own specific property values, functionality should be shared across objects. Let's pool the functionality into a single place in memory rather than duplicate it every time we create a new object with the constructor.

var Car = function(loc) {
	var obj = {};
	obj.loc = loc;
	obj.move = move;
	return obj;
};

var move = function() {
	obj.loc++; // "obj" not in the scope!
};

To avoid the problem of obj no longer being in the scope of the function when extracting the function move from the constructor, and hence not having access to the property loc, we use the special Javascript keyword this, which always refers to the object "at the left of the dot" at call time, when a function is called on an object.

var move = function() {
	this.loc++;
};

var myCar = Car(3);
myCar.move();
console.log(myCar.loc); // 4

In the above, when the move function is run on myCar, the keyword this will be bound to myCar (cf. "left of the dot" rule) and so this.loc++ will increment the value 3.

But what if we have multiple methods? We would have to list all of them in two places. Let's store the methods somewhere and add them to the object being created when we create it.

var Car = function(loc) {
	var obj = {};
	obj.loc = loc;
	for (var f in methods) {
		obj.f = methods[f];
	}
	return obj;
};

var methods = {
	move: function() {
		this.loc++;
	},
	on: function() {
		// Some code
	},
	off: function() {
		// Some code
	}
};

However, storing methods in the global scope like that is not a good practice. We don't want everyone to be able to access those methods, but only objects of that class. Could we somehow store the methods at the level of the class itself? But, you might think, the class definition is a function! Well, actually, in Javascript, functions can also hold properties:

var f = function(name) {
	console.log("Hello, " + name);
};

f.a = "Hello";

f("John"); // Hello, John
console.log(f.a); // Hello

Therefore, let's store the methods as a property of the Car class/function:

var Car = function(loc) {
	var obj = {};
	obj.loc = loc;
	for (var f in Car.methods) {
		obj.f = Car.methods[f];
	}
	return obj;
};

Car.methods = {
	move: function() {
		this.loc++;
	},
	on: function() {
		// Some code
	},
	off: function() {
		// Some code
	}
};

The for loop seems kind of weird. Do we really need to copy all these pointers to all methods? Actually, Javascript has the concept of delegation between objects. Defining a delegation relationship of object b to object a means that a failed property lookup in b (trying to access in b a property that b does not have will be forwarded to a lookup on a.

var a = {someProperty: 2};
var b = Object.create(a); // This is the syntax to establish a delegation relationship

console.log(b.someProperty); // 2

Therefore, we can use that technique in our Car class to avoid copying pointers to each method:

var Car = function(loc) {
	var obj = Object.create(Car.methods);
	obj.loc = loc;
	return obj;
};

Car.methods = {
	move: function() {
		this.loc++;
	},
	on: function() {
		// Some code
	},
	off: function() {
		// Some code
	}
};

Since this overall pattern is so common, Javascript simplified it and built it in. Every function in Javascript has a built-in property called prototype that will hold the methods in case you turn that function into a class.

var f = function(name) {
	console.log("Hello, " + name);
};

console.log(f.prototype); // {}

Therefore:

Car.prototype.move = function() {
	this.loc++;
};

Car.prototype.on = function() {
	// Some code
};

Car.prototype.off = function() {
	// Some code
};

var Car = function(loc) {
	var obj = Object.create(Car.prototype); // Repetitive
	obj.loc = loc;
	return obj; // Repetitive
};

Furthermore, if we use the keyword new when creating an instance of car, Javascript will add for you the repetitive lines, so you don't need to write them yourself. Also, it will bind the special keyword this to the object holding the methods of the class.

var Car = function(loc) {
	this = Object.create(Car.prototype); // Added by Javascript
	this.loc = loc;
	return this; // Added by Javascript
};

var myCar = new Car(4);

Finally, we get the standard way of writing a class in Javascript:

var Car = function(loc) {
	this.loc = loc;
};

Car.prototype.move = function() {
	this.loc++;
};

var myCar = new Car(4); // Instantiating a car object

This pattern is known as the pseudo-classical pattern of writing classes in Javascript. The name comes from the fact that it imitates the pattern of other classical object-oriented programming languages.

Clone this wiki locally