Class : Template of collection of related data and functionality (Added recently)
Object : Instance of class. Before the inclusion of class, js normally implemented object directly by defining it in several ways
Collection of related data and functionality
Syntax patter of an object :
const objectName = {
member1Name: member1Value,
member2Name: member2Value,
member3Name: member3Value
};
The variable type of the member of object can be anything from integer variables to strings, arrays and functions.
Object is composed of series of keys and values -> key : value
Variables in Objects are called properties
Functions in Objects are called methods
Ex)
const person = {
name: ['Bob', 'Smith'],
age: 32,
gender: 'male',
interests: ['music', 'skiing'],
bio: function() {
alert(this.name[0] + ' ' + this.name[1] + ' is ' + this.age + ' years old. He likes ' + this.interests[0] + ' and ' + this.interests[1] + '.');
},
greeting: function() {
alert('Hi! I\'m ' + this.name[0] + '.');
}
};
The following example is reffered to an object literal as we have written out the object contents (the values of variable and functions) as we have created it -> Contrast to objects instantiated from classes
Dot notation is used to access the encapsulated object's properties and methods.
Setting an object as another object's member is also possible. Access by using 2 dot notations :
//name was originally an array in the person class
//name = ['Bob', 'Smith'],
name : {
first : 'Bob',
last : 'Smith'
},
person.name.first
person.name.last
Another way to acess object properties :
//Instead of using
person.age
person.name.first
//Use bracket notations
person['age']
person['name']['first']
Note : always add '' within the property name
Normally use the dot notation to get property value that is defined beforehand and bracket notation for property values that are defined during runtime
Ex)
function printValue(obj, key) {
console.log(obj[key]);
}
printValue(ellie, 'name');
The following function passes the 'name' argument to the printValue
function and the property value is defined during the code runtime. Therefore only obj[key]
would be able to modify the value.
Set the value of object members by declaring the member you want to set using dot or bracket notation
person.age = 45;
person['name']['last'] = 'Cratchit';
It is also possible to create new members of the object after defining the object:
//Declare new properties and methods
person['eyes'] = 'hazel';
person.farewell = function() { alert("Bye everybody!"); }
Users are also able to delete properties later :
delete person.age;
this
keyword refers to the current object the code is being written inside.
Ex)
greeting: function() {
alert('Hi! I\'m ' + this.name.first + '.');
}
The following function's this
refers to the person
object itself.
this
is good as it always ensures that the correct values are used when a member's contest changes : There might be more than 1 object instances which may cause confusion if you use the object name rather than this
Basic idea of OOP : Use objects to model real world things that we want to represent inside our programs.
Ex) Display information about students and teachers at school
First, we would define the gerenic data and functionality of a class ofperson. Info related to a person would be name, age, gender etc. and also include a function to introduce themselves.
This is refered to an abstraction : Create simple model of a more complex thing. There is no direct info about each variables however the structure is only defined.
From our class, we can create object instances - objects that contain the data and functionality definied in the class.
When an object instance is created from a class, the class's constructor function is run to create it.
Instantiation : Object instance is instantiated from class
However in the follwing example, we want more specific types of people : students and teachers
In OOP it is possible to create new classes based on other classes - These new child classes(=subclasses) can be made to inherit the data and code features of parent classes.
Therefore you can reuse functionality common to all the object tupes (and no need to duplicate it). Were functionality defers, you can define specialized features directly
After defining these new classes, it is possible to make the object instances of the following child classes
There are several ways to create a new object :
Object.create
methodObject()
constructorObject initializers are creating objects with leteral notatoion. The syntax is :
var obj = { property_1: value_1, // property_# may be an identifier...
2: value_2, // or a number...
// ...,
'property n': value_n }; // or a string
Object initializers are expressions, and each object initializer results in a new object being created whenever the statement in which it appears is executed. Identical object initializers create distinct objects that will not compare to each other as equal -> are instances of Object
.
Constructor functions are used to define and initialize objects and their features. Constructors provide the means to create many objects effectively.
Ex) Without a constructor, to define the properties of a person :
function createNewPerson(name) {
const obj = {};
obj.name = name;
obj.greeting = function() {
alert('Hi! I\'m ' + obj.name + '.');
};
return obj;
}
const salva = createNewPerson('Salva');
salva.name;
salva.greeting();
Would have to define the function to create a person and also have to call the properties and methods additionally to make changes.
Using a constructor would make things much simpler by :
function Person(name) {
this.name = name;
this.greeting = function() {
alert('Hi! I\'m ' + this.name + '.');
};
}
A constructor does not retrun anything or explicitly creat an object - defines properties and methods. The this
is used to point to the object instances created.
To call a constructor to create objects :
let person1 = new Person('Bob');
let person2 = new Person('Sarah');
The new
is used to tell the browser we want to create a new object instance : Instantiate an Object
The Object()
represents a constructor for generic objects. It normally generates an empty project
The following
let person1 = new Object();
would store an empty object in the person1
variable. Adding the properties and methods to the object can be done later by using dot notation :
person1.name = 'Chris';
person1['age'] = 38;
Another way is to pass the object literals as a parameter to the Object()
constructor :
let person1 = new Object({
name: 'Chris',
age: 38,
greeting: function() {
alert('Hi! I\'m ' + this.name + '.');
}
});
For simplicity, it would be sometimes prefered to create objects without first creating constructors (ex: for situations were you are only creating few instances of object).
You can create a new object, using an existing object as the prototype of the newly created object
let person2 = Object.create(person1);
//Note that person1 is an object (not an object instance) in the following example
The following person1
's constructor is copied to the new person2
object. person2
would then be able to access the properties and methods
Note : The create() method can be used both to copy an object and also an object instance
The in
operator checks the existence of a property in an object and returns a boolean value
console.log('name' in Yoonseo); //return true
console.log('success' in Yoonseo); //return true
console.log('failure' in Yoonseo); //return false
for...in
syntax is used to iterate through an object till it finds the appropriate property
for(key in Yoonseo) {
console.log(key);
}
The following function iterates and gets all of the key in object to be shown in console
It is available to copy an object to another empty object by using Object.assign()
Object.assign(cloneObject, oritinalObject);
It is also possible to overwrite more than 1 functions
const fruit1 = {color : 'red'};
const fruit2 = {color : 'blue', size: 'big'};
const mixed = Object.assign({}, fruit1, fruit2);
The empty object is overwrited by 2 functions fruit2 and fruit1. fruit1 and fruit2 both has the color property. The one with higher priority is fruit 2 as the objects on the right side overwrites the one in the left.
Using Object.values()
, it returns an array of the values stored in the object inserted as a parameter
Using Object.keys()
, it returns an array of the keys stored in the object inserted as a parameter
JavaScript is often described as a prototype-based language — to provide inheritance, objects can have a prototype object, which acts as a template object that it inherits methods and properties from.
An object's prototype object may also have a prototype. The following relationship can repeat which makes a prototype chain
For an object instance made, a link is formed between the instance and its prototypes. Properties and methods are found by walkng up the chain of prototype.
Ex) We have a person1
object instance, instantiated from the class Person
:
function Person(first, last, age, gender, interests) {
// property and method definitions
this.name = {
'first': first,
'last' : last
};
this.age = age;
this.gender = gender;
}
//Object instance
let person1 = new Person('Bob', 'Smith', 32, 'male', ['music', 'skiing']);
In the person1
object, not only the user is able to access properties and methods defined in the constructor Person
but is also able to access the Object
prototype's method and properties.
If you call a method or property defined in the Object
prototype
ex)
person1.valueOf()
valueOf()
returns the value of the object it is called on. The process is :
Not all of the properties and methods defined in the Object
class can be accessed by the person1
object. Some are inherited and some aren't
The inherited ones are the ones defined on the prototype
property : Ones that begin wih Object.prototype.
The prototype
property's value is an object, storing properties and methods that we want to be inherited by objects further down the prototype chain.
Object.prototype.toString()
and Object.prototype.valueOf()
are available to any object types that inherit from Object.prototype
Person()
constructor aswellThe prototype property of an object instance can be accessed as it is defined as __proto__
in one of the properties
Previously the create()
function has been described to be used to create a new object instance by copying the class of an existing object instance :
let person2 = Object.create(person1);
What it actually is doing is creating a new object from a specified prototype object. In the following example, person2
is created by using person1
as a prototype object
person2.__proto__
Following code will return the person1
object
Every constructor function has a prototype
property(property that can be accessed to the inherited object instances) which is an object containing a constructor
property
The following constructor
property points to the original constructor form.
In the previous example, properties defined on the Person.prototype
property can be accessed by the instance objects created using the Person()
constructor. Therefore the constructor
property is available on both person1
and person2
Ex)
person1.constructor
person2.constructor
Both of the codes return the Person()
constructor.
It is also possible to put parenthesis at end of the constructor
property to create another object instance from that constructor (as the constructor
is a function after all
Ex)
let person3 = new person1.constructor('Karen', 'Stephenson', 26, 'female', ['playing drums', 'mountain climbing']);
The following constructor
property can be useful when you want to create a new instance and don't have a reference to the original constructor easily available for some reason.
Also if you have an object instance and you want to return the name of the constructor it is an instance of, you can use the following:
instanceName.constructor.name
By modifying the prototype
property of a constructor function -> methods added to the prototype are then available to be used by all object intances created by the constructor
Ex) Add a new function to Person()
constructor's prototype :
Person.prototype.farewell = function() {
alert(this.name.first + ' has left the building. Bye for now!');
};
//Object insatnce of Person() can access the newly added function
person1.farewell();
Note : Although the object instance is instantiated before the newly included method to the prototype, the instantiated object can still access to the method.
The prototype
property is rarely used to define or modify properties of prototypes due to the lack of flexibility. Ex)
Person.prototype.fullName = this.name.first + ' ' + this.name.last;
The following code is to define a person's name by using name.first
and name.last
. However this is done outside of the constructor function and therefore the this
keyword would be referencing the global scope and therefore return undefined
. Therefore it would be better to define properties inside the constructor.
Properties are noramlly defined within the constructor functions. prototype
is normally used to defined the methods of a constructor for a better desing of code to seperate properties and methods.
// Constructor with property definitions
function Test(a, b, c, d) {
// property definitions
}
// First method definition
Test.prototype.x = function() { ... };
// Second method definition
Test.prototype.y = function() { ... };
// etc.
Inheritance by using protype chains involved built-int browser functions (ex : Object()). How would javascript create an object that inherits from another object.
The following process is described by using an example
function Person(first, last, age, gender, interests) {
this.name = {
first,
last
};
this.age = age;
this.gender = gender;
this.interests = interests;
};
Person.prototype.greeting = function() {
alert('Hi! I\'m ' + this.name.first + '.');
};
The following constructor defines all the properties inside function and methods in global scope using prototype
We would want to create a Teacher
class that inherits all members from Person
but also include :
1. A new property, subject
2. An updated greeting
method, with a more formal greeting sentence
Define a Teacher()
constructor :
function Teacher(first, last, age, gender, interests, subject) {
Person.call(this, first, last, age, gender, interests);
//New property that parent object does not have
this.subject = subject;
}
.call()
function allows you to call a constructor function defined somewhere else, but in the current context -> inheritthis
in the 1st parameter specifies the value (in this case the object from Teacher
class) to use when running the functionTeacher()
function to take same parameters as the Person()
constructor therefore specify them all as parameters in call()
function.subject
property is a property that Person()
does not haveThe newly defined constructor of Teacher()
has a prototype
property, which by default just contains an object with a reference to the constructor function itself -> constructor
property. It does not contain the methods of Person constructor's prototype
property.
Therefore we need to get Teacher()
to inherit the methods defined on Person()
's prototype
Teacher.prototype = Object.create(Person.prototype);
The following code uses create()
to create a new object and make it the value of Teacher.prototype
. The created new object has Person.prototype
as its prototype and inherits all methods available.
Note that the constructor
prototype in the Teacher.prototype
also points to Person()
as it has been inherited from Person.prototype
.
The following problem can be fixed by setting the source code using :
Object.defineProperty(Teacher.prototype, 'constructor', {
value: Teacher,
enumerable: false, // so that it does not appear in 'for in' loop
writable: true });
for the Teacher.prototype.constructor
to return Teacher()
as expected
To add a new method, the easiest way would be to define it on Teacher()
's prototype :
Teacher.prototype.greeting = function() {
let prefix;
alert('Hello. My name is ' + prefix + ' ' + this.name.last + ', and I teach ' + this.subject + '.');
};
There are mainly 4 types of property/methods in JS
Object.keys
in which Object
is the class)static
class User {
static staticMethod() {
alert(this === User);
}
}
User.staticMethod(); // Accessed by using class name
IMPORTANT : Acknowledge the difference between the 1st and 2nd type -> 1st is defined in constructor and 2nd is defined in prototype.
Getter : Method that gets the value of a specific property. Effective when you want to reflect the status of an internal variable witout requiring the use of explicit method calls.
Setter : Method that sets the value of a specific property or whenever a specified property is attempted to be changed.
Defining a getter and setter on new objects in object initializers are done by including the get
and set
keywords in code
class Teacher extends Person {
constructor(first, last, age, gender, interests, subject, grade) {
super(first, last, age, gender, interests);
// subject and grade are specific to Teacher
this.subject = subject;
this.grade = grade;
}
get subject() {
return this._subject;
}
set subject(newSubject) {
this._subject = newSubject;
}
}
The following code has a getter and setter for the subject
property.
Note : After a getter and setter is defined for a specific property, when you try to get the value of the property or access it to change the value via this.
, automatically the getter and setter function is called.
When you try to get the subject
property value by this.subject
, the get subject()
getter is called.
When you try to change the subject
property value by modifying using this.subject
, the set subject()
setter is called.
This leads to an infinite loop if the getter and setter is formed by :
get subject() {
return this.subject;
}
set subject(newSubject) {
this.subject = newSubject;
}
where the getter and setter functions both have the this.subject
code. This leads to an infinite loop as the code calls the getter or setter. Therefore the getter and setter should have a different syntax for the property : this._subjcet
Although the syntax is different, the getter and setter function for the subject
property is set to subject
therefore the syntax defined within the getter and setter does not matter.
ECMAScript 2015 introduces class syntax to JavaScript as a way to write reusable classes using easier, cleaner syntax, which is more similar to classes in C++ or Java.
Does the same functionality of the previous object, object instances and prototypes but in a much more easier code structure
The general structure of the new syntax :
class Person {
constructor(first, last, age, gender, interests) {
this.name = {
first,
last
};
this.age = age;
this.gender = gender;
this.interests = interests;
}
//Reduces the need to add by using prototypes as it will automatically add the function in prototype
greeting() {
console.log(`Hi! I'm ${this.name.first}`);
};
farewell() {
console.log(`${this.name.first} has left the building. Bye for now!`);
};
}
The class
statement indicates that we are creating a new class :
constructor()
defines a constructor functiongreeting()
and farewell()
are class methods : The benefit of the class syntax is that it reduces the need to add by using prototypes as it will automatically add the function in prototypeThen instantiate object instances using the new
operator :
let han = new Person('Han', 'Solo', 25, 'male', ['Smuggling']);
han.greeting();
To extend the properties and methods from the Person
class to Teacher
class using modern class syntax :
class Teacher extends Person {
//Newly added property and methods for Teacher class
constructor(subject, grade) {
this.subject = subject;
this.grade = grade;
}
}
We use the extends
keyword to tell the JS the calss we want to base our new class on. However unlike the old style where the new
operator initializes the this
to the new allocated object, it isn't automatically initialized for a class defined by extends
For sub-classes, this
initialization to a newly allocaated object is always dependant on by calling the parent class constructor. Therefore the super()
operator is used to call the parent's constructor.
Also it is required for the sub-class to inherit properties from the parent class. Therefore include arguments in the super()
operator, passing the necessary arguments to initialize the parent class properties in our sub-class thereby inheriting it.
class Teacher extends Person {
constructor(first, last, age, gender, interests, subject, grade) {
// Now 'this' is initialized by calling the parent constructor.
super(first, last, age, gender, interests);
// subject and grade are specific to Teacher
this.subject = subject;
this.grade = grade;
}
}
instanceof
is a code that returns a boolean value based on whether a certain object is an instance of a class. Ex)
console.log(rectangle instanceof Rectangle); //Return true
console.log(triangle instanceof Rectangle); //Return false
console.log(triangle instanceof Object); //Return true (as every object instance has Object in hierarchy)
HTTP(Hypertext Transfer Protocal) is a protocal transmitting hypermedia documents. It was designed for communication between web browsers and web servers.
JSON(JavaScript Object Notation) is a standard text-based format for representing structured data, based on js object. It is normally used for transmitting data in web between client and server (ex : Send some data from server to client)
Although it resembles JS object literal syntax, it can be used independently from JS and many programming environments feature the ability to read(parse) and generate JSON.
JSON exists as a string - Useful when you want to transmit data across a network. The transmitted data needs to be converted to a native JS object when you want to access the data.
-> JavaScript provides a global JSON object that has methods available for converting between the two
-> The similar structure between JSON and normal JS objects make it easy for conversion between JSON data to JS object
JSON is composed of strings in which the general format very much resembles JavaScript object literal format. It is possible to include basic data types in JSON like a standard Javascript object.
Ex)
{
"squadName": "Super hero squad",
"homeTown": "Metro City",
"formed": 2016,
"active": true,
"members": [
{
"name": "Molecule Man",
"powers": [
"Radiation resistance",
"Turning tiny",
"Radiation blast"
]
},
{
"name": "Madame Uppercut",
"powers": [
"Million tonne punch",
"Damage resistance",
"Superhuman reflexes"
]
}
]
}
If we load this string to a JS program, ex) parsed it into a variable superHeroes
we could access the data inside it using dot and bracket notation:
superHeroes.homeTown
superHeroes['active']
To access further down the hierarchy, you have to chain the property name together with array incexes together. To access the 3rd power of the 2nd hero :
superHeroes['members'][1]['powers'][2]
The following example describes the process of how the web page uses JSON to send it to server and request for a JS object to be able to use them.
For the example we use the JSON defined previously, which has info about superheros.
We use an API called XMLHttpRequest (XHR) to obtain the JSON. The XMLHttpRequest
object allows us to make network requests to retrieve resources from server visa JS.
1) First store the URL of the JSON into a variable
let requestURL = 'https://mdn.github.io/learning-area/javascript/oojs/json/superheroes.json';
2) To request, we need to create a new request object instance from the XMLHttpRequest constructor, using the new
keyword.
let request = new XMLHttpRequest();
3) Now we need to open the request using the open() method.
request.open('GET', requestURL);
requestURL
defines the URL to make request to 4) Set the responseType
to JSON so that XHR knows that the server will be returning JSON, and that this should be converted to JS object.
Then send the request with send()
method
request.responseType = 'json';
request.send();
request.onload = function() {
const superHeroes = request.response;
populateHeader(superHeroes);
showHeroes(superHeroes);
}
The above examples used the XHR request to conver the JSON response directly into a JavaScript object in the server automatically.
However sometimes, automatic conversion is not available and therefore
The process of transfering an object to JSON file : serialize
-> stringify()
: Accepts an object as parameter, and returns the equivalent JSON string
Process of transfering the JSON file back to an object : deserialize
-> parse()
: Accepts a JSON string as parameter, and returns the corresponding JS object
//Javascript object defined
const rabbit = {
name : 'tori',
size : null,
birthDate : new Date(),
jump: () => {
console.log(`${name} can jump!`);
},
};
//1. Object to JSON : serialize
//Convert the javascript object defined into a JSON string
//The new Date() returns a string of the date and birthDate has a string value of the date stored
//The method is truncated and not included in the string
json = JSON.stringify(rabbit);
console.log(json);
//Using call back function to choose specific values within the string
//output : {"name" : "tori"}
json = JSON.stringify(rabbit, ['name']);
console.log(json);
//Using call back function to modify string values of key
//change name value to "ellie"
json = JSON.stringify(rabbit, (key,value) => {
console.log(`key: ${key}, value: ${value}`);
//If key is name, return string of 'ellie', else return the value of each key
return key === 'name'? 'ellie' : value;
});
//2. JSON to object
json = JSON.stringify(rabbit);
const obj = JSON.parse(json);
//The "json" JSON file obtained from the rabbit object is parsed
//obj stores the parsed "json" in the form of JS object
console.log(obj);
//The following method causes an error
//This is because obj is parsed from "json" which does not contain a method as it is a JSON file
obj.jump();
//The rabbit object can use the getter function defined in the Date() object
//obj object can't as the "json" stores birthDate key's value as a string type (not object type) -> has no getter()
console.log(rabbit.birthDate.getDate());
console.log(obj.birthDate.getDate());
//Add the following code while obj parses json
//When key value is birthDate, returns a new Date() object (not the original string value stored in json)
const obj = JSON.parse(json, (key,value) => {
console.log(`key: ${key}, value: ${value}`);
return key === 'birthDate' ? new Date(value) : value;
});