JavaScript Course 4: Objects: Difference between revisions

From WikiMLT
m (Стадий: 6 [Фаза:Утвърждаване, Статус:Утвърден]; Категория:JavaScript)
 
m (Text replacement - "mlw-continue" to "code-continue")
 
Line 30: Line 30:
In JavaScript Objects are dynamic, so we can add additional properties and methods to them, despite of they are defined by keywords <code>var</code>, <code>let</code>  or <code>const</code>. When we define an Object by <code>const</code> that means the type of the variable that holds the ''object'' is <code>const</code> and we can't change that type, but we can modify the created Object itself - changing the properties and methods of the Object .  
In JavaScript Objects are dynamic, so we can add additional properties and methods to them, despite of they are defined by keywords <code>var</code>, <code>let</code>  or <code>const</code>. When we define an Object by <code>const</code> that means the type of the variable that holds the ''object'' is <code>const</code> and we can't change that type, but we can modify the created Object itself - changing the properties and methods of the Object .  


In order to delete a '''member''' ('''property''' or '''method''') of an Object we can use the delete operator in the following way. <syntaxhighlight lang="javascript" class="mlw-continue">
In order to delete a '''member''' ('''property''' or '''method''') of an Object we can use the delete operator in the following way. <syntaxhighlight lang="javascript" class="code-continue">
delete circle.name;
delete circle.name;
</syntaxhighlight>
</syntaxhighlight>
Line 44: Line 44:


== Literal syntax of Object definition ==
== Literal syntax of Object definition ==
<syntaxhighlight lang="javascript" class="mlw-continue">
<syntaxhighlight lang="javascript" class="code-continue">
const circle = {
const circle = {
     "name": "Circle 1",        // Property of type String
     "name": "Circle 1",        // Property of type String
Line 57: Line 57:
   }
   }
};
};
</syntaxhighlight><syntaxhighlight lang="javascript" class="mlw-continue">
</syntaxhighlight><syntaxhighlight lang="javascript" class="code-continue">
console.log(circle);
console.log(circle);
</syntaxhighlight><syntaxhighlight lang="shell-session">
</syntaxhighlight><syntaxhighlight lang="shell-session">
Line 66: Line 66:


=== Dot notation ===
=== Dot notation ===
Call and assign a Property with Dot notation.<syntaxhighlight lang="javascript" class="mlw-continue">
Call and assign a Property with Dot notation.<syntaxhighlight lang="javascript" class="code-continue">
console.log(circle.name);
console.log(circle.name);
</syntaxhighlight><syntaxhighlight lang="shell-session">
</syntaxhighlight><syntaxhighlight lang="shell-session">
Circle 1
Circle 1
</syntaxhighlight><syntaxhighlight lang="javascript" class="mlw-continue">
</syntaxhighlight><syntaxhighlight lang="javascript" class="code-continue">
circle.isVisible = false;
circle.isVisible = false;
console.log(circle.isVisible);
console.log(circle.isVisible);
Line 78: Line 78:


=== Bracket notation ===
=== Bracket notation ===
Call and assign a Property with Bracket notation.<syntaxhighlight lang="javascript" class="mlw-continue">
Call and assign a Property with Bracket notation.<syntaxhighlight lang="javascript" class="code-continue">
console.log(circle['location']);
console.log(circle['location']);
</syntaxhighlight><syntaxhighlight lang="shell-session">
</syntaxhighlight><syntaxhighlight lang="shell-session">
{x: 1, y: 1}
{x: 1, y: 1}
</syntaxhighlight><syntaxhighlight lang="javascript" class="mlw-continue">
</syntaxhighlight><syntaxhighlight lang="javascript" class="code-continue">
circle.location['x'] = 2;
circle.location['x'] = 2;
circle.location.y = 3;
circle.location.y = 3;
Line 91: Line 91:


=== Methods and Dot notation ===
=== Methods and Dot notation ===
When a Function is a part of an Object in the terms of OOP we calling this Function a Method. Methods could be called and defined only with Dot notation.<syntaxhighlight lang="javascript" class="mlw-continue">
When a Function is a part of an Object in the terms of OOP we calling this Function a Method. Methods could be called and defined only with Dot notation.<syntaxhighlight lang="javascript" class="code-continue">
circle.draw();
circle.draw();
</syntaxhighlight><syntaxhighlight lang="shell-session">
</syntaxhighlight><syntaxhighlight lang="shell-session">
Draw a circle with: 2 3 1
Draw a circle with: 2 3 1
</syntaxhighlight><syntaxhighlight lang="javascript" class="mlw-continue">
</syntaxhighlight><syntaxhighlight lang="javascript" class="code-continue">
circle.radius = 2;
circle.radius = 2;
circle.area = function() {
circle.area = function() {
Line 112: Line 112:
Step 1, move the object definition inside :the Factory function and return it as output of that function:
Step 1, move the object definition inside :the Factory function and return it as output of that function:
|
|
<syntaxhighlight lang="javascript" class="mlw-continue">
<syntaxhighlight lang="javascript" class="code-continue">
function createCircle() {
function createCircle() {
     const circle = {
     const circle = {
Line 133: Line 133:
Step 2, simplify the above and just return the object definition.
Step 2, simplify the above and just return the object definition.
|
|
<syntaxhighlight lang="javascript" class="mlw-continue">
<syntaxhighlight lang="javascript" class="code-continue">
function createCircle() {
function createCircle() {
     return {
     return {
Line 153: Line 153:
Step 3, convert hard codded values as parameters, which values will be supply as arguments when we calling the Factory function.
Step 3, convert hard codded values as parameters, which values will be supply as arguments when we calling the Factory function.
|
|
<syntaxhighlight lang="javascript" class="mlw-continue">
<syntaxhighlight lang="javascript" class="code-continue">
function createCircle(name, radius, location, isVisible) {
function createCircle(name, radius, location, isVisible) {
     return {
     return {
Line 167: Line 167:
</syntaxhighlight>
</syntaxhighlight>
|l=#Step 3}}
|l=#Step 3}}
{{collapse|Step 4, in modern JS if the key and the value are the same we can make our code shorter, and removing the value and simply adding the key.|<syntaxhighlight lang="javascript" class="mlw-continue">
{{collapse|Step 4, in modern JS if the key and the value are the same we can make our code shorter, and removing the value and simply adding the key.|<syntaxhighlight lang="javascript" class="code-continue">
function createCircle(name, radius, location, isVisible) {
function createCircle(name, radius, location, isVisible) {
     return {
     return {
Line 185: Line 185:
Step 5, simplify the Methods definitions, like we define a function outside of an object, but we can dropping the ''function'' keyword.
Step 5, simplify the Methods definitions, like we define a function outside of an object, but we can dropping the ''function'' keyword.
|
|
<syntaxhighlight lang="javascript" class="mlw-continue">
<syntaxhighlight lang="javascript" class="code-continue">
function createCircle(name, radius, location, isVisible) {
function createCircle(name, radius, location, isVisible) {
     return {
     return {
Line 198: Line 198:
}
}
</syntaxhighlight>
</syntaxhighlight>
|l=#The final result, Step 5|c=false}}'''Use the Factory function.'''<syntaxhighlight lang="javascript" class="mlw-continue">
|l=#The final result, Step 5|c=false}}'''Use the Factory function.'''<syntaxhighlight lang="javascript" class="code-continue">
const circle1 = createCircle("Circle 1", 2, {x: 1, y: 2}, true);
const circle1 = createCircle("Circle 1", 2, {x: 1, y: 2}, true);
</syntaxhighlight><syntaxhighlight lang="javascript" class="mlw-continue">
</syntaxhighlight><syntaxhighlight lang="javascript" class="code-continue">
console.log(circle1);
console.log(circle1);
</syntaxhighlight><syntaxhighlight lang="shell-session">
</syntaxhighlight><syntaxhighlight lang="shell-session">
{name: 'Circle 1', radius: 2, location: {…}, visible: true, draw: ƒ}
{name: 'Circle 1', radius: 2, location: {…}, visible: true, draw: ƒ}
</syntaxhighlight><syntaxhighlight lang="javascript" class="mlw-continue">
</syntaxhighlight><syntaxhighlight lang="javascript" class="code-continue">
const circle2 = createCircle("Circle 2", 4, {x: 2, y: 2}, true);
const circle2 = createCircle("Circle 2", 4, {x: 2, y: 2}, true);
</syntaxhighlight><syntaxhighlight lang="javascript" class="mlw-continue">
</syntaxhighlight><syntaxhighlight lang="javascript" class="code-continue">
console.log(circle2);
console.log(circle2);
</syntaxhighlight><syntaxhighlight lang="shell-session">
</syntaxhighlight><syntaxhighlight lang="shell-session">
Line 214: Line 214:
The purpose of the Constructor functions is the same as the Factory functions - they produce Objects, it's just another approach.
The purpose of the Constructor functions is the same as the Factory functions - they produce Objects, it's just another approach.


The naming convention for the Factory functions is: <code>PascalNotation</code><syntaxhighlight lang="javascript" class="mlw-continue">
The naming convention for the Factory functions is: <code>PascalNotation</code><syntaxhighlight lang="javascript" class="code-continue">
function Circle(name, radius, location, isVisible) {
function Circle(name, radius, location, isVisible) {
     this.name = name;
     this.name = name;
Line 228: Line 228:
const circle3 = new Circle("Circle 3", 6, {x: 2, y: 4}, true);
const circle3 = new Circle("Circle 3", 6, {x: 2, y: 4}, true);
</syntaxhighlight>
</syntaxhighlight>
<syntaxhighlight lang="javascript" class="mlw-continue">
<syntaxhighlight lang="javascript" class="code-continue">
console.log(circle3);
console.log(circle3);
</syntaxhighlight><syntaxhighlight lang="shell-session">
</syntaxhighlight><syntaxhighlight lang="shell-session">
Circle {name: 'Circle 3', radius: 6, location: {…}, isVisible: true, draw: ƒ}
Circle {name: 'Circle 3', radius: 6, location: {…}, isVisible: true, draw: ƒ}
</syntaxhighlight><syntaxhighlight lang="javascript" class="mlw-continue">
</syntaxhighlight><syntaxhighlight lang="javascript" class="code-continue">
circle3.draw();
circle3.draw();
</syntaxhighlight><syntaxhighlight lang="shell-session">
</syntaxhighlight><syntaxhighlight lang="shell-session">
Line 251: Line 251:
An important difference between '''function declarations''' and '''class declarations''' is that while functions can be called in code that appears before they are defined, classes must be defined before they can be constructed. Code like the following will throw a <code>ReferenceError</code>:
An important difference between '''function declarations''' and '''class declarations''' is that while functions can be called in code that appears before they are defined, classes must be defined before they can be constructed. Code like the following will throw a <code>ReferenceError</code>:


The naming convention for the Classes (as the Factory functions) is: <code>PascalNotation</code><syntaxhighlight lang="javascript" class="mlw-continue">
The naming convention for the Classes (as the Factory functions) is: <code>PascalNotation</code><syntaxhighlight lang="javascript" class="code-continue">
class Circle {
class Circle {
     constructor(name, radius, location, isVisible) {
     constructor(name, radius, location, isVisible) {
Line 267: Line 267:
const circle4 = new Circle("Circle 4", 8, {x: 6, y: 6}, false);
const circle4 = new Circle("Circle 4", 8, {x: 6, y: 6}, false);
</syntaxhighlight>
</syntaxhighlight>
<syntaxhighlight lang="javascript" class="mlw-continue">
<syntaxhighlight lang="javascript" class="code-continue">
console.log(circle4);
console.log(circle4);
</syntaxhighlight><syntaxhighlight lang="shell-session">
</syntaxhighlight><syntaxhighlight lang="shell-session">
Line 273: Line 273:
</syntaxhighlight>
</syntaxhighlight>
== Constructor Property ==
== Constructor Property ==
Every Object has a constructor property that show the function that we use to create the object.<syntaxhighlight lang="javascript" class="mlw-continue">
Every Object has a constructor property that show the function that we use to create the object.<syntaxhighlight lang="javascript" class="code-continue">
let x = {};
let x = {};
console.log(x.constructor);
console.log(x.constructor);
</syntaxhighlight><syntaxhighlight lang="shell-session">
</syntaxhighlight><syntaxhighlight lang="shell-session">
ƒ Object() {[native code]}
ƒ Object() {[native code]}
</syntaxhighlight><syntaxhighlight lang="javascript" class="mlw-continue">
</syntaxhighlight><syntaxhighlight lang="javascript" class="code-continue">
let x = new String('ABC');
let x = new String('ABC');
console.log(x.constructor);
console.log(x.constructor);
</syntaxhighlight><syntaxhighlight lang="shell-session">
</syntaxhighlight><syntaxhighlight lang="shell-session">
ƒ String() {[native code]}
ƒ String() {[native code]}
</syntaxhighlight><syntaxhighlight lang="javascript" class="mlw-continue">
</syntaxhighlight><syntaxhighlight lang="javascript" class="code-continue">
let x = 'ABC';
let x = 'ABC';
console.log(x.constructor);
console.log(x.constructor);
Line 299: Line 299:
}
}
</syntaxhighlight>
</syntaxhighlight>
<syntaxhighlight lang="javascript" class="mlw-continue">
<syntaxhighlight lang="javascript" class="code-continue">
console.log(Circle.name);
console.log(Circle.name);
</syntaxhighlight><syntaxhighlight lang="shell-session">
</syntaxhighlight><syntaxhighlight lang="shell-session">
'Circle'
'Circle'
</syntaxhighlight><syntaxhighlight lang="javascript" class="mlw-continue">
</syntaxhighlight><syntaxhighlight lang="javascript" class="code-continue">
console.log(Circle.length);  // will return the number of arguments
console.log(Circle.length);  // will return the number of arguments
</syntaxhighlight><syntaxhighlight lang="shell-session">
</syntaxhighlight><syntaxhighlight lang="shell-session">
1
1
</syntaxhighlight><syntaxhighlight lang="javascript" class="mlw-continue">
</syntaxhighlight><syntaxhighlight lang="javascript" class="code-continue">
console.log(Circle.constructor);  // will return the constructor function
console.log(Circle.constructor);  // will return the constructor function
</syntaxhighlight><syntaxhighlight lang="shell-session">
</syntaxhighlight><syntaxhighlight lang="shell-session">
Line 322: Line 322:


'''1.A.''' Example with primitives - when we copy the value of a Primitive type we create an independent variable:
'''1.A.''' Example with primitives - when we copy the value of a Primitive type we create an independent variable:
<syntaxhighlight lang="javascript" class="mlw-continue">
<syntaxhighlight lang="javascript" class="code-continue">
let x = 10;
let x = 10;
let y = x;
let y = x;
Line 333: Line 333:


'''1.B.''' Example with references - when we copy the value or Reference type we copy the reference, not the value:
'''1.B.''' Example with references - when we copy the value or Reference type we copy the reference, not the value:
<syntaxhighlight lang="javascript" class="mlw-continue">
<syntaxhighlight lang="javascript" class="code-continue">
let x = {value: 10};
let x = {value: 10};
let y = x;
let y = x;
x.value = 20;
x.value = 20;
</syntaxhighlight>
</syntaxhighlight>
<syntaxhighlight lang="javascript" class="mlw-continue">
<syntaxhighlight lang="javascript" class="code-continue">
console.log(x);
console.log(x);
</syntaxhighlight>
</syntaxhighlight>
<syntaxhighlight lang="shell-session" class="mlw-continue">
<syntaxhighlight lang="shell-session" class="code-continue">
{value: 20}
{value: 20}
</syntaxhighlight>
</syntaxhighlight>
<syntaxhighlight lang="javascript" class="mlw-continue">
<syntaxhighlight lang="javascript" class="code-continue">
console.log(y);
console.log(y);
</syntaxhighlight>
</syntaxhighlight>
Line 352: Line 352:


'''2.A.''' Another example with Primitive types:
'''2.A.''' Another example with Primitive types:
<syntaxhighlight lang="javascript" class="mlw-continue">
<syntaxhighlight lang="javascript" class="code-continue">
let number = 10;
let number = 10;


Line 361: Line 361:
increase(number);
increase(number);
</syntaxhighlight>
</syntaxhighlight>
<syntaxhighlight lang="javascript" class="mlw-continue">
<syntaxhighlight lang="javascript" class="code-continue">
console.log(number);
console.log(number);
</syntaxhighlight>
</syntaxhighlight>
<syntaxhighlight lang="shell-session" class="mlw-continue">
<syntaxhighlight lang="shell-session" class="code-continue">
10
10
</syntaxhighlight>When we pass the variable <code>number</code> as an argument of the function <code>increase(number)</code>, there is created a ''local variable'' (inside the function) that is completely different of the ''global variable'' <code>number</code>, so the value of the global variable is not changed.
</syntaxhighlight>When we pass the variable <code>number</code> as an argument of the function <code>increase(number)</code>, there is created a ''local variable'' (inside the function) that is completely different of the ''global variable'' <code>number</code>, so the value of the global variable is not changed.


'''2.B.''' Another example with Reference types:
'''2.B.''' Another example with Reference types:
<syntaxhighlight lang="javascript" class="mlw-continue">
<syntaxhighlight lang="javascript" class="code-continue">
let object = {value: 10};
let object = {value: 10};


Line 378: Line 378:
increase(object);
increase(object);
</syntaxhighlight>
</syntaxhighlight>
<syntaxhighlight lang="javascript" class="mlw-continue">
<syntaxhighlight lang="javascript" class="code-continue">
console.log(object);
console.log(object);
</syntaxhighlight>
</syntaxhighlight>
<syntaxhighlight lang="shell-session" class="mlw-continue">
<syntaxhighlight lang="shell-session" class="code-continue">
{value: 11}
{value: 11}
</syntaxhighlight>In this example wen we pass the <code>object</code> as argument to the function it is passed as its reference. So we have two variables <code>object</code> and <code>obj</code> that pointing to the same (internal JS) object.
</syntaxhighlight>In this example wen we pass the <code>object</code> as argument to the function it is passed as its reference. So we have two variables <code>object</code> and <code>obj</code> that pointing to the same (internal JS) object.
Line 391: Line 391:
     draw() {console.log("Draw...");}
     draw() {console.log("Draw...");}
};
};
</syntaxhighlight><syntaxhighlight lang="javascript" class="mlw-continue">
</syntaxhighlight><syntaxhighlight lang="javascript" class="code-continue">
for (let key in circle)
for (let key in circle)
     console.log(`${key} : ${circle[key]}`);
     console.log(`${key} : ${circle[key]}`);
Line 398: Line 398:
radius : 1
radius : 1
draw : draw() {console.log("Draw...");}
draw : draw() {console.log("Draw...");}
</syntaxhighlight><syntaxhighlight lang="javascript" class="mlw-continue">
</syntaxhighlight><syntaxhighlight lang="javascript" class="code-continue">
// Object.keys(circle) returns an Array of keys of the circle 'object', which array is iterative
// Object.keys(circle) returns an Array of keys of the circle 'object', which array is iterative
for (let key of Object.keys(circle))
for (let key of Object.keys(circle))
Line 407: Line 407:
radius : 1
radius : 1
draw : draw() {console.log("Draw...");}
draw : draw() {console.log("Draw...");}
</syntaxhighlight><syntaxhighlight lang="javascript" class="mlw-continue">
</syntaxhighlight><syntaxhighlight lang="javascript" class="code-continue">
// Object.keys(circle) returns an Array of keys of the circle 'object', which array is iterative
// Object.keys(circle) returns an Array of keys of the circle 'object', which array is iterative
for (let entry of Object.entries(circle))
for (let entry of Object.entries(circle))
Line 416: Line 416:
(2) ['radius', 1]
(2) ['radius', 1]
(2) ['draw', ƒ]
(2) ['draw', ƒ]
</syntaxhighlight>If given property or method exists example:<syntaxhighlight lang="javascript" class="mlw-continue">
</syntaxhighlight>If given property or method exists example:<syntaxhighlight lang="javascript" class="code-continue">
if ('radius' in circle) console.log('YES');
if ('radius' in circle) console.log('YES');
</syntaxhighlight>
</syntaxhighlight>
Line 429: Line 429:
     draw() {console.log("Draw...");}
     draw() {console.log("Draw...");}
};
};
</syntaxhighlight>The old approach - iterate over the keys of an exiting object and copy their values to the new object.<syntaxhighlight lang="javascript" class="mlw-continue">
</syntaxhighlight>The old approach - iterate over the keys of an exiting object and copy their values to the new object.<syntaxhighlight lang="javascript" class="code-continue">
const another = {};
const another = {};
for (let key in circle)
for (let key in circle)
     another[key] = circle[key];
     another[key] = circle[key];
</syntaxhighlight><syntaxhighlight lang="javascript" class="mlw-continue">
</syntaxhighlight><syntaxhighlight lang="javascript" class="code-continue">
console.log(another);
console.log(another);


Line 439: Line 439:
<syntaxhighlight lang="shell-session">
<syntaxhighlight lang="shell-session">
{radius: 1, draw: ƒ}
{radius: 1, draw: ƒ}
</syntaxhighlight>The modern approach - use <code>Object.assign()</code> which copies all properties and methods from one or more objects to a new object.<syntaxhighlight lang="javascript" class="mlw-continue">
</syntaxhighlight>The modern approach - use <code>Object.assign()</code> which copies all properties and methods from one or more objects to a new object.<syntaxhighlight lang="javascript" class="code-continue">
const another = Object.assign({}, circle);
const another = Object.assign({}, circle);
</syntaxhighlight><syntaxhighlight lang="javascript" class="mlw-continue">
</syntaxhighlight><syntaxhighlight lang="javascript" class="code-continue">
console.log(another);
console.log(another);


Line 447: Line 447:
<syntaxhighlight lang="shell-session">
<syntaxhighlight lang="shell-session">
{radius: 1, draw: ƒ}
{radius: 1, draw: ƒ}
</syntaxhighlight>Clone an Object and add an additional property or method to the new object.<syntaxhighlight lang="javascript" class="mlw-continue">
</syntaxhighlight>Clone an Object and add an additional property or method to the new object.<syntaxhighlight lang="javascript" class="code-continue">
const another = Object.assign({"color": "yellow"}, circle);
const another = Object.assign({"color": "yellow"}, circle);
</syntaxhighlight><syntaxhighlight lang="javascript" class="mlw-continue">
</syntaxhighlight><syntaxhighlight lang="javascript" class="code-continue">
console.log(another);
console.log(another);


Line 458: Line 458:


A simile and elegant way to clone an object - by using the Spread operator: <code class="noTypo">...</code>
A simile and elegant way to clone an object - by using the Spread operator: <code class="noTypo">...</code>
<syntaxhighlight lang="javascript" class="mlw-continue">
<syntaxhighlight lang="javascript" class="code-continue">
const another = {...circle};
const another = {...circle};
</syntaxhighlight><syntaxhighlight lang="javascript" class="mlw-continue">
</syntaxhighlight><syntaxhighlight lang="javascript" class="code-continue">
console.log(another);  
console.log(another);  



Latest revision as of 08:29, 26 September 2022

Ref­er­ences

See al­so:

Ba­sics

Ob­ject ori­ent­ed pro­gram­ming (OOP) is a style of pro­gram­ming where we see a pro­gram as a col­lec­tion of Ob­jects, that talk to each oth­er to per­form some func­tion­al­i­ty. The Ob­jects has:

  • Prop­er­ties – prim­i­tives de­fined by "keys": and "values",
  • Meth­ods – in­ter­nal functions() that op­er­ates with the prop­er­ties of the ob­ject.

We can ac­cess the Prop­er­ties of an Ob­ject via:

  • Dot no­ta­tion: object.proprtyName;
  • Brack­et no­ta­tion: object['proprtyName'];

Us­ing Dot no­ta­tion is clean­er and eas­i­er, but the Brack­et no­ta­tion could be used when we want to pass vari­able in the place of the key – i.e. when when us­ing a loop or so.

We can ac­cess the Meth­ods of an Ob­ject via:

  • Dot no­ta­tion (on­ly):
    • object.methodName();
    • object.methodName = function() {…};

In JavaScript Ob­jects are dy­nam­ic, so we can add ad­di­tion­al prop­er­ties and meth­ods to them, de­spite of they are de­fined by key­words var, let or con­st. When we de­fine an Ob­ject by con­st that means the type of the vari­able that holds the ob­ject is con­st and we can't change that type, but we can mod­i­fy the cre­at­ed Ob­ject it­self – chang­ing the prop­er­ties and meth­ods of the Ob­ject .

In or­der to delete a mem­ber (prop­er­ty or method) of an Ob­ject we can use the delete op­er­a­tor in the fol­low­ing way.

delete circle.name;

Ways to cre­ate an Ob­ject in JavaScript

With JavaScript, you can de­fine and cre­ate your own ob­jects. There are dif­fer­ent ways to cre­ate new ob­jects:

  1. Cre­ate a sin­gle ob­ject, us­ing an Ob­ject lit­er­al.
  2. Cre­ate a sin­gle ob­ject, with the key­word new.
  3. De­fine Ob­ject Fac­to­ry func­tion, and then gen­er­ate a new ob­ject by this func­tion.
  4. De­fine an Ob­ject Con­struc­tor func­tion, and then cre­ate ob­jects of the con­struct­ed type.
  5. Cre­ate an ob­ject us­ing Object.create().
  6. ES6 Class­es.

Lit­er­al syn­tax of Ob­ject de­f­i­n­i­tion

const circle = {
    "name": "Circle 1",         // Property of type String
    "radius": 1,                // Property of type Number
    "location": {             // Property of type Object
        "x": 1,
        "y": 1
   },
    "isVisible": true,          // Property of type Boolean
    "draw": function() {       // Method: a property of type Function
        console.log("Draw a circle with:", this.location.x, this.location.y, this.radius);
   }
};
console.log(circle);
{name: 'Circle 1', radius: 1, location: {…}, isVisible: true, draw: ƒ}

Ac­cess Prop­er­ties and Meth­ods

Dot no­ta­tion

Call and as­sign a Prop­er­ty with Dot no­ta­tion.

console.log(circle.name);
Circle 1
circle.isVisible = false;
console.log(circle.isVisible);
false

Brack­et no­ta­tion

Call and as­sign a Prop­er­ty with Brack­et no­ta­tion.

console.log(circle['location']);
{x: 1, y: 1}
circle.location['x'] = 2;
circle.location.y = 3;
console.log(circle.location.x, circle.location['y']);
2 3

Meth­ods and Dot no­ta­tion

When a Func­tion is a part of an Ob­ject in the terms of OOP we call­ing this Func­tion a Method. Meth­ods could be called and de­fined on­ly with Dot no­ta­tion.

circle.draw();
Draw a circle with: 2 3 1
circle.radius = 2;
circle.area = function() {
    return this.radius * this.radius * 3.14;
};
console.log(circle.area());
12.56

Fac­to­ry Func­tions for Ob­jects de­f­i­n­i­tion

Just like a fac­to­ry pro­duce prod­ucts, the Fac­to­ry func­tions pro­duce Ob­jects. Here is how to trans­form the Ob­ject lit­er­al de­f­i­n­i­tion in­to a fac­to­ry func­tion.

The nam­ing con­ven­tion for the Fac­to­ry func­tions is: kamel­No­ta­tion

Step 1, move the ob­ject de­f­i­n­i­tion in­side :the Fac­to­ry func­tion and re­turn it as out­put of that func­tion:

#Step 1
function createCircle() {
    const circle = {
        "name": "Circle 1",         // Property of type String
        "radius": 1,                // Property of type Number
        "location": {             // Property of type Object
            "x": 1,
            "y": 1
       },
        "isVisible": true,          // Property of type Boolean
        "draw": function() {       // Method: a property of type Function
            console.log("Draw a circle with:", this.location.x, this.location.y, this.radius);
       }
   };
    return circle;
}

Step 2, sim­pli­fy the above and just re­turn the ob­ject de­f­i­n­i­tion.

#Step 2
function createCircle() {
    return {
        "name": "Circle 1",         // Property of type String
        "radius": 1,                // Property of type Number
        "location": {             // Property of type Object
            "x": 1,
            "y": 1
       },
        "isVisible": true,          // Property of type Boolean
        "draw": function() {       // Method: a property of type Function
            console.log("Draw a circle with:", this.location.x, this.location.y, this.radius);
       }
   };
}

Step 3, con­vert hard cod­ded val­ues as pa­ra­me­ters, which val­ues will be sup­ply as ar­gu­ments when we call­ing the Fac­to­ry func­tion.

#Step 3
function createCircle(name, radius, location, isVisible) {
    return {
        "name": name,    
        "radius": radius,
        "location":  location,
        "isVisible": visible,
        "draw": function() {
            console.log("Draw a circle with:", this.location.x, this.location.y, this.radius);
       }
   };
}

Step 4, in mod­ern JS if the key and the val­ue are the same we can make our code short­er, and re­mov­ing the val­ue and sim­ply adding the key.

#Step 4
function createCircle(name, radius, location, isVisible) {
    return {
        name,    
        radius,
        location,
        visible,
        "draw": function() {
            console.log("Draw a circle with:", this.location.x, this.location.y, this.radius);
       }
   };
}

Step 5, sim­pli­fy the Meth­ods de­f­i­n­i­tions, like we de­fine a func­tion out­side of an ob­ject, but we can drop­ping the func­tion key­word.

#The fi­nal re­sult, Step 5
function createCircle(name, radius, location, isVisible) {
    return {
        name,    
        radius,
        location,
        visible,
        draw() {
            console.log("Draw a circle with:", this.location.x, this.location.y, this.radius);
       }
   };
}

Use the Fac­to­ry func­tion.

const circle1 = createCircle("Circle 1", 2, {x: 1, y: 2}, true);
console.log(circle1);
{name: 'Circle 1', radius: 2, location: {…}, visible: true, draw: ƒ}
const circle2 = createCircle("Circle 2", 4, {x: 2, y: 2}, true);
console.log(circle2);
{name: 'Circle 2', radius: 4, location: {…}, visible: true, draw: ƒ}

Con­struc­tor Func­tions for Ob­jects de­f­i­n­i­tion

The pur­pose of the Con­struc­tor func­tions is the same as the Fac­to­ry func­tions – they pro­duce Ob­jects, it's just an­oth­er ap­proach.

The nam­ing con­ven­tion for the Fac­to­ry func­tions is: Pas­cal­No­ta­tion

function Circle(name, radius, location, isVisible) {
    this.name = name;
    this.radius = radius;
    this.location = location;
    this.isVisible = isVisible;
    this.draw = function() {
        console.log("Draw a circle with:", this.location.x, this.location.y, this.radius);
   };
}

Use the Con­struc­tor func­tion.

const circle3 = new Circle("Circle 3", 6, {x: 2, y: 4}, true);
console.log(circle3);
Circle {name: 'Circle 3', radius: 6, location: {…}, isVisible: true, draw: ƒ}
circle3.draw();
Draw a circle with: 2 4 6

When we use the new op­er­a­tor three things hap­pen:

  1. The new op­er­a­tor cre­ates an emp­ty JavaScript Ob­ject, some­thing like this: con­stant x = {};
  2. Then new set this of the Con­struc­tor func­tion to point to the new emp­ty Ob­ject.
  3. Fi­nal­ly new re­turns the new Ob­ject from the con­struc­tor func­tion, but we don't need ex­plic­it­ly add a re­turn state­ment.

Class­es for Ob­jects de­f­i­n­i­tion

The pur­pose of the Class­es is the same as the Fac­to­ry and Con­struc­tor func­tions – they pro­duce Ob­jects. It's just an­oth­er mod­ern ap­proach de­fined in ES6 (ES2015).

Class­es are a tem­plate for cre­at­ing ob­jects. They en­cap­su­late da­ta with code to work on that da­ta. Class­es in JS are built on pro­to­types but al­so have some syn­tax and se­man­tics that are not shared with ES5 class-like se­man­tics.

Class­es are in fact "spe­cial func­tions", and just as you can de­fine func­tion ex­pres­sions and func­tion de­c­la­ra­tions, the class syn­tax has two com­po­nents: class ex­pres­sions and class de­c­la­ra­tions.

An im­por­tant dif­fer­ence be­tween func­tion de­c­la­ra­tions and class de­c­la­ra­tions is that while func­tions can be called in code that ap­pears be­fore they are de­fined, class­es must be de­fined be­fore they can be con­struct­ed. Code like the fol­low­ing will throw a Ref­er­enceEr­ror:

The nam­ing con­ven­tion for the Class­es (as the Fac­to­ry func­tions) is: Pas­cal­No­ta­tion

class Circle {
    constructor(name, radius, location, isVisible) {
        this.name = name;
        this.radius = radius;
        this.location = location;
        this.isVisible = isVisible;
    }
    draw() {
        console.log("Draw a circle with:", this.location.x, this.location.y, this.radius);
    }
}

Use the Con­struc­tor func­tion. The us­age is the same as the Con­struc­tor func­tions by us­ing the new op­er­a­tor.

const circle4 = new Circle("Circle 4", 8, {x: 6, y: 6}, false);
console.log(circle4);
Circle {name: 'Circle 4', radius: 8, location: {…}, isVisible: false, draw: ƒ}

Con­struc­tor Prop­er­ty

Every Ob­ject has a con­struc­tor prop­er­ty that show the func­tion that we use to cre­ate the ob­ject.

let x = {};
console.log(x.constructor);
ƒ Object() {[native code]}
let x = new String('ABC');
console.log(x.constructor);
ƒ String() {[native code]}
let x = 'ABC';
console.log(x.constructor);
ƒ String() {[native code]}

Func­tions and Ar­rays are Ob­jects

In JavaScript the Func­tions (and Ar­rays) are al­so Ob­jects. There is a built-in con­struc­tor func­tion called Func­tion that cre­ates the ob­jects of the func­tions. So the Func­tions al­so have meth­ods and prop­er­ties.

function Circle(radius) {
    this.radius = radius;
    this.draw = function() {
        console.log("Draw circle radius:", this.radius);
   }
}
console.log(Circle.name);
'Circle'
console.log(Circle.length);  // will return the number of arguments
1
console.log(Circle.constructor);  // will return the constructor function
ƒ Function() {[native code]}

See al­so Call and Ap­ply meth­ods:

Val­ue vs Ref­er­ence types

The Val­ue types, al­so called Prim­i­tive types – Strings, Num­bers, Booleans, un­de­fined, null, Sym­bol – holds the val­ue in­side the vari­able of the prim­i­tive. In oth­er hand the Ref­er­ence types – Ob­jects, Ar­rays, Func­tions – holds a rev­er­ence to an in­ter­nal variable(s) where the ac­tu­al val­ue is stored.

Prim­i­tives are copied by their val­ue. Ob­jects (ref­er­ence types) are copied by their ref­er­ence.

1.A. Ex­am­ple with prim­i­tives – when we copy the val­ue of a Prim­i­tive type we cre­ate an in­de­pen­dent vari­able:

let x = 10;
let y = x;
x = 20;
console.log(x, y); // We can see 'x' and 'y' are two indepentant variables
20 10

1.B. Ex­am­ple with ref­er­ences – when we copy the val­ue or Ref­er­ence type we copy the ref­er­ence, not the val­ue:

let x = {value: 10};
let y = x;
x.value = 20;
console.log(x);
{value: 20}
console.log(y);
{value: 20}

2.A. An­oth­er ex­am­ple with Prim­i­tive types:

let number = 10;

function increase(num) {
    num++;
}

increase(number);
console.log(number);
10

When we pass the vari­able num­ber as an ar­gu­ment of the func­tion increase(number), there is cre­at­ed a lo­cal vari­able (in­side the func­tion) that is com­plete­ly dif­fer­ent of the glob­al vari­able num­ber, so the val­ue of the glob­al vari­able is not changed.

2.B. An­oth­er ex­am­ple with Ref­er­ence types:

let object = {value: 10};

function increase(obj) {
    obj.value++;
}

increase(object);
console.log(object);
{value: 11}

In this ex­am­ple wen we pass the ob­ject as ar­gu­ment to the func­tion it is passed as its ref­er­ence. So we have two vari­ables ob­ject and obj that point­ing to the same (in­ter­nal JS) ob­ject.

Enu­mer­at­ing Prop­er­ties of an Ob­ject

const circle = {
    "radius": 1,
    draw() {console.log("Draw...");}
};
for (let key in circle)
    console.log(`${key} : ${circle[key]}`);
radius : 1
draw : draw() {console.log("Draw...");}
// Object.keys(circle) returns an Array of keys of the circle 'object', which array is iterative
for (let key of Object.keys(circle))
    console.log(`${key} : ${circle[key]}`);
radius : 1
draw : draw() {console.log("Draw...");}
// Object.keys(circle) returns an Array of keys of the circle 'object', which array is iterative
for (let entry of Object.entries(circle))
    console.log(entry);
(2) ['radius', 1]
(2) ['draw', ƒ]

If giv­en prop­er­ty or method ex­ists ex­am­ple:

if ('radius' in circle) console.log('YES');
YES

Clone an Ob­ject

const circle = {
    "radius": 1,
    draw() {console.log("Draw...");}
};

The old ap­proach – it­er­ate over the keys of an ex­it­ing ob­ject and copy their val­ues to the new ob­ject.

const another = {};
for (let key in circle)
    another[key] = circle[key];
console.log(another);
{radius: 1, draw: ƒ}

The mod­ern ap­proach – use Object.assign() which copies all prop­er­ties and meth­ods from one or more ob­jects to a new ob­ject.

const another = Object.assign({}, circle);
console.log(another);
{radius: 1, draw: ƒ}

Clone an Ob­ject and add an ad­di­tion­al prop­er­ty or method to the new ob­ject.

const another = Object.assign({"color": "yellow"}, circle);
console.log(another);
{color: 'yellow', radius: 1, draw: ƒ}

A sim­i­le and el­e­gant way to clone an ob­ject – by us­ing the Spread op­er­a­tor: ...

const another = {...circle};
console.log(another);
{radius: 1, draw: ƒ}