We are going to start working with OOP JavaScript! There are few very different things from the rest of the OOP world (For example, there are no classes)
- A good start is this reference - https://developer.mozilla.org/en-US/docs/Web/JavaScript/Introduction_to_Object-Oriented_JavaScript
- Here is a video (27 minutes) that covers all OOP concepts in JavaScript
We can make a new object of a given type, by providing the so-called "constructor function".
This is a normal JavaScript function, that we write with uppercase to indicate that it will be a constructor for an object.
For example:
function Person(firstName, secondName, age) {
this.firstName = firstName;
this.secondName = secondName;
this.age = age;
}
// we call the function with this
var p = new Person("Bobi", "Donchev", 20);Now the variable p is a object from the type Person
// accessing:
p.firstName;
p.secondName;
p.age;
// modifying
p.firstName = "Ivo";
p.secondName = "Donchev";
p.age = 21;If we want to add methods to our Person class, we can attach functions to this:
function Person(firstName, secondName, age) {
this.firstName = firstName;
this.secondName = secondName;
this.age = age;
this.getName = function() {
return [firstName, secondName].join(" ");
}
this.sayHello = function() {
return ["I", "am", this.getName()].join(" ");
}
}Now if we want to use those methods, we can access them with the dot notation:
var p = new Person("Bobi", "Donchev", 20);
p.getName(); // "Bobi Donchev"
p.sayHello(); // "I am Bobi Donchev"In JavaScript, every object have something, that is called a prototype.
The prototype is simply another Object, "linked" to our current object.
For example, in JavaScript, every object "inherits" from Object. But since we have no syntax for classes or inheritence, it is done by linking the prototype chain.
Check this:
Every object, has a hidden __proto__ property, which links to:
- First, its own prototype - we will see next that is this
- In the current object's prototype, there is another
__proto__, which links to the prototype ofObject, where allObjectmethods are linked.
Which leads us to the next stage - where should we add methods? To this or to our prototype?
A good topic on the difference between this.method vs prototype.method can be found here - http://stackoverflow.com/questions/310870/use-of-prototype-vs-this-in-javascript
If we add methods to this, they will be created every time we call the constructor function with new
But when we create a new object, the method, attached to this will alocate it's own memory.
This means that if we create 10 instances of a given class, we will have 10 different instances for that method, attached to this.
If we want to have only 1 instance of the method for all object instances, we have to add it to the prototype of the object!
Every object has a prototype object, which is one for all instances.
If we want to add a method to the prototype, we can do the following:
function Person(firstName, secondName, age) {
this.firstName = firstName;
this.secondName = secondName;
this.age = age;
this.getName = function() {
return [firstName, secondName].join(" ");
}
}
Person.prototype.sayHello = function() {
return ["I", "am", this.getName()].join(" ");
}Now, sayHello is attached to the prototype and the function wont be created with every instance of Person
We can still call sayHello() the standard way:
var p = new Person("Bobi", "Donchev", 20);
p.getName(); // "Bobi Donchev"
p.sayHello(); // "I am Bobi Donchev"this in the prototype function is the same this, which we use in the constructor function.
A basic closure example with a counter:
var counter = (function() {
var count = 0;
return function() {
count = count + 1;
return count;
}
} () );
counter(); // 1
counter(); // 2
counter(); // 3
// and so on ...The important thing here is that the returned function sees the private count and keeps the value in memory, even after we have exited the funciton.
If we want to create a literal object with private parts, we enclose the literal object with an anonymous function, that calls itself immediately.
This is called an IIFE (Immediately Invoked Function Expression)
Here is an example with a basePerson with private parts:
// function closure
var basePerson = (function() {
var _private = {
personName : ""
};
return {
setName : function(name) {
_private.personName = name;
},
getName : function() {
return _private.personName;
}
};
} () );In our exampe, _private is seen only inside the enclosed function.
The function returns a object literal, where we expose the public parts.
The magic here is that the functions inside the public parts see _private, but private cannot be used or seen anywhere else.
"use strict";
function Person(firstName, secondName, age) {
var initials = [firstName[0], secondName[0]].join("");
this.getName = function() {
return [firstName, secondName].join(" ");
}
this.getAge = function() {
return age;
}
this.getInitials = function() {
return initials;
}
}
Person.prototype.sayHello = function() {
return "I AM " + this.getName();
};
Person.prototype.toString = function() {
return this.getName();
};
function Student(firstName, secondName, age) {
Person.call(this, firstName, secondName, age);
}
Student.prototype = Object.create(Person.prototype);
Student.prototype.constructor = Student;
Student.prototype.toString = function() {
return Person.prototype.toString.call(this) + "I am a student";
}
var s = new Student("Bobi", "Donchev", 20);
console.log(s.toString());