JavaScript OOP Course 2: Objects Recap: Difference between revisions

From WikiMLT
m (Стадий: 6 [Фаза:Утвърждаване, Статус:Утвърден]; Категория:JavaScript)
 
m (Text replacement - "mlw-continue" to "code-continue")
 
Line 10: Line 10:


== Object Literals ==
== Object Literals ==
<syntaxhighlight lang="javascript" class="mlw-continue">
<syntaxhighlight lang="javascript" class="code-continue">
const circle = {};  
const circle = {};  
</syntaxhighlight>The Objects are collections of <code>key:</code> <code>value</code> pears.<syntaxhighlight lang="javascript" class="mlw-continue">
</syntaxhighlight>The Objects are collections of <code>key:</code> <code>value</code> pears.<syntaxhighlight lang="javascript" class="code-continue">
const circle = {
const circle = {
     radius: 1,                  // Property, Number
     radius: 1,                  // Property, Number
Line 25: Line 25:
</syntaxhighlight>The <code>circle</code> object above has '''3 members''': '''2 properties''' (<code>radius</code> and <code>location</code>) and '''1 method''' (<code>draw</code>). The '''properties''' are used to '''hold values'''. The '''methods''' are used to '''hold logic'''. When an Object has one or more methods we can say it has behavior.
</syntaxhighlight>The <code>circle</code> object above has '''3 members''': '''2 properties''' (<code>radius</code> and <code>location</code>) and '''1 method''' (<code>draw</code>). The '''properties''' are used to '''hold values'''. The '''methods''' are used to '''hold logic'''. When an Object has one or more methods we can say it has behavior.


The syntax of method definition could be simplified by removing the function keyword and the colon delimiter.<syntaxhighlight lang="javascript" class="mlw-continue">
The syntax of method definition could be simplified by removing the function keyword and the colon delimiter.<syntaxhighlight lang="javascript" class="code-continue">
const circle = {
const circle = {
     radius: 1,                  // Property, Number
     radius: 1,                  // Property, Number
Line 36: Line 36:
     }
     }
};
};
</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 43: Line 43:


== Factories ==
== Factories ==
The Factory functions produce Objects. In the above example is used ES6 feature where when the names of the key and the variable that will produce the value are identical, instead of <code>property: property,</code> we can write just <code>property</code>, within the object returned by the factory function.<syntaxhighlight lang="javascript" class="mlw-continue">
The Factory functions produce Objects. In the above example is used ES6 feature where when the names of the key and the variable that will produce the value are identical, instead of <code>property: property,</code> we can write just <code>property</code>, within the object returned by the factory function.<syntaxhighlight lang="javascript" class="code-continue">
function createCircle(radius, location) {
function createCircle(radius, location) {
     return {
     return {
Line 53: Line 53:
     }
     }
}
}
</syntaxhighlight><syntaxhighlight lang="javascript" class="mlw-continue">
</syntaxhighlight><syntaxhighlight lang="javascript" class="code-continue">
const circle1 = createCircle(1, {x: 1, y: 1});
const circle1 = createCircle(1, {x: 1, y: 1});
const circle2 = createCircle(2, {x: 1, y: 1});
const circle2 = createCircle(2, {x: 1, y: 1});
</syntaxhighlight><syntaxhighlight lang="javascript" class="mlw-continue">
</syntaxhighlight><syntaxhighlight lang="javascript" class="code-continue">
console.log(circle1, circle2);
console.log(circle1, circle2);
</syntaxhighlight><syntaxhighlight lang="shell-session">
</syntaxhighlight><syntaxhighlight lang="shell-session">
Line 64: Line 64:


== Constructors ==
== Constructors ==
Constructor functions are another way to create an object. Unlike the Factory functions which return an object itself, the Constructor functions are used with the <code>new</code> operator that creates the new object.<syntaxhighlight lang="javascript" class="mlw-continue">
Constructor functions are another way to create an object. Unlike the Factory functions which return an object itself, the Constructor functions are used with the <code>new</code> operator that creates the new object.<syntaxhighlight lang="javascript" class="code-continue">
function Circle(radius, location) {
function Circle(radius, location) {
     this.radius = radius;
     this.radius = radius;
Line 72: Line 72:
     }
     }
}
}
</syntaxhighlight><syntaxhighlight lang="javascript" class="mlw-continue">
</syntaxhighlight><syntaxhighlight lang="javascript" class="code-continue">
const circle1 = new Circle(1, {x: 1, y: 1});
const circle1 = new Circle(1, {x: 1, y: 1});
const circle2 = new Circle(1, {x: 1, y: 1});
const circle2 = new Circle(1, {x: 1, y: 1});
</syntaxhighlight><syntaxhighlight lang="javascript" class="mlw-continue">
</syntaxhighlight><syntaxhighlight lang="javascript" class="code-continue">
console.log(circle1, circle2);
console.log(circle1, circle2);
</syntaxhighlight><syntaxhighlight lang="shell-session">
</syntaxhighlight><syntaxhighlight lang="shell-session">
Circle {radius: 1, location: {…}, draw: ƒ}
Circle {radius: 1, location: {…}, draw: ƒ}
Circle {radius: 2, location: {…}, draw: ƒ}
Circle {radius: 2, location: {…}, draw: ƒ}
</syntaxhighlight>The Constructor functions are the base for proper understanding the '''ES6 Classes'''. The ES6 Classes will be discussed in a separate chapter, but let's see how the Class equivalent to the above Constructor function looks like.<syntaxhighlight lang="javascript" class="mlw-continue">
</syntaxhighlight>The Constructor functions are the base for proper understanding the '''ES6 Classes'''. The ES6 Classes will be discussed in a separate chapter, but let's see how the Class equivalent to the above Constructor function looks like.<syntaxhighlight lang="javascript" class="code-continue">
function Circle(radius, location) {
function Circle(radius, location) {
     this.radius = radius;
     this.radius = radius;
Line 88: Line 88:
     }
     }
}
}
</syntaxhighlight><syntaxhighlight lang="javascript" class="mlw-continue">
</syntaxhighlight><syntaxhighlight lang="javascript" class="code-continue">
const circle1 = new Circle(1, {x: 1, y: 1});
const circle1 = new Circle(1, {x: 1, y: 1});
const circle2 = new Circle(1, {x: 1, y: 1});
const circle2 = new Circle(1, {x: 1, y: 1});
</syntaxhighlight><syntaxhighlight lang="javascript" class="mlw-continue">
</syntaxhighlight><syntaxhighlight lang="javascript" class="code-continue">
console.log(circle1, circle2);
console.log(circle1, circle2);
</syntaxhighlight><syntaxhighlight lang="shell-session">
</syntaxhighlight><syntaxhighlight lang="shell-session">
Line 101: Line 101:
Every object in JavaScript has a property called Constructor. It references to the function that was used to construct (or create) the object.
Every object in JavaScript has a property called Constructor. It references to the function that was used to construct (or create) the object.


'''Object created by ES6 Class'''<syntaxhighlight lang="javascript" class="mlw-continue">
'''Object created by ES6 Class'''<syntaxhighlight lang="javascript" class="code-continue">
class Circle {
class Circle {
     constructor(radius) {
     constructor(radius) {
Line 109: Line 109:
const circle = new Circle(1);
const circle = new Circle(1);


</syntaxhighlight><syntaxhighlight lang="javascript" class="mlw-continue">
</syntaxhighlight><syntaxhighlight lang="javascript" class="code-continue">
circle.constructor;
circle.constructor;
</syntaxhighlight><syntaxhighlight lang="shell-session">
</syntaxhighlight><syntaxhighlight lang="shell-session">
Line 117: Line 117:
     }
     }
}
}
</syntaxhighlight>'''Object created by Constructor function'''<syntaxhighlight lang="javascript" class="mlw-continue">
</syntaxhighlight>'''Object created by Constructor function'''<syntaxhighlight lang="javascript" class="code-continue">
function Circle(radius) {
function Circle(radius) {
     this.radius = radius;
     this.radius = radius;
Line 123: Line 123:
const circle = new Circle(1);
const circle = new Circle(1);


</syntaxhighlight><syntaxhighlight lang="javascript" class="mlw-continue">
</syntaxhighlight><syntaxhighlight lang="javascript" class="code-continue">
circle.constructor;
circle.constructor;
</syntaxhighlight><syntaxhighlight lang="shell-session">
</syntaxhighlight><syntaxhighlight lang="shell-session">
Line 129: Line 129:
     this.radius = radius;
     this.radius = radius;
}
}
</syntaxhighlight>'''Object created by Factory function'''<syntaxhighlight lang="javascript" class="mlw-continue">
</syntaxhighlight>'''Object created by Factory function'''<syntaxhighlight lang="javascript" class="code-continue">
function createCircle(radius) {
function createCircle(radius) {
     return { radius }
     return { radius }
Line 135: Line 135:
const circle = createCircle(1);
const circle = createCircle(1);


</syntaxhighlight><syntaxhighlight lang="javascript" class="mlw-continue">
</syntaxhighlight><syntaxhighlight lang="javascript" class="code-continue">
circle.constructor;
circle.constructor;
</syntaxhighlight><syntaxhighlight lang="shell-session">
</syntaxhighlight><syntaxhighlight lang="shell-session">
ƒ Object() { [native code] }
ƒ Object() { [native code] }
</syntaxhighlight>'''Object created by Object Literals'''<syntaxhighlight lang="javascript" class="mlw-continue">
</syntaxhighlight>'''Object created by Object Literals'''<syntaxhighlight lang="javascript" class="code-continue">
const circle = { radius: 1 };
const circle = { radius: 1 };


</syntaxhighlight><syntaxhighlight lang="javascript" class="mlw-continue">
</syntaxhighlight><syntaxhighlight lang="javascript" class="code-continue">
circle.constructor;
circle.constructor;
</syntaxhighlight><syntaxhighlight lang="shell-session">
</syntaxhighlight><syntaxhighlight lang="shell-session">
Line 157: Line 157:


== Functions are Objects ==
== Functions are Objects ==
The Functions in JavaScript are objects. And they have built-in methods and properties.<syntaxhighlight lang="javascript" class="mlw-continue">
The Functions in JavaScript are objects. And they have built-in methods and properties.<syntaxhighlight lang="javascript" class="code-continue">
function Circle(radius) {
function Circle(radius) {
     this.radius = radius;
     this.radius = radius;
}
}


</syntaxhighlight><syntaxhighlight lang="javascript" class="mlw-continue">
</syntaxhighlight><syntaxhighlight lang="javascript" class="code-continue">
Circle.name;
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">
Circle.length;  // return the number of the arguments
Circle.length;  // return the number of the 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">
Circle.constructor
Circle.constructor
</syntaxhighlight><syntaxhighlight lang="shell-session">
</syntaxhighlight><syntaxhighlight lang="shell-session">
ƒ Function() { [native code] }
ƒ Function() { [native code] }
</syntaxhighlight>There is Constructor function, called <code>Function()</code>, that creates the functions when we define them in literals. So when we define a function in the following way.<syntaxhighlight lang="javascript" class="mlw-continue">
</syntaxhighlight>There is Constructor function, called <code>Function()</code>, that creates the functions when we define them in literals. So when we define a function in the following way.<syntaxhighlight lang="javascript" class="code-continue">
function Circle(radius) {
function Circle(radius) {
     this.radius = radius;
     this.radius = radius;
}
}


</syntaxhighlight>In the background the JavaScript engine does something like this.<syntaxhighlight lang="javascript" class="mlw-continue">
</syntaxhighlight>In the background the JavaScript engine does something like this.<syntaxhighlight lang="javascript" class="code-continue">
const Circle = new Function('radius', `this.radius = radius;`);
const Circle = new Function('radius', `this.radius = radius;`);
</syntaxhighlight><syntaxhighlight lang="javascript" class="mlw-continue">
</syntaxhighlight><syntaxhighlight lang="javascript" class="code-continue">
const circle = new Circle(1);
const circle = new Circle(1);
</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 192: Line 192:


* See also: [[JavaScript Course 6: Functions#Changing this|JavaScript Functions: Changing <code>this</code>]]
* See also: [[JavaScript Course 6: Functions#Changing this|JavaScript Functions: Changing <code>this</code>]]
<syntaxhighlight lang="javascript" class="mlw-continue">
<syntaxhighlight lang="javascript" class="code-continue">
function Circle(radius) {
function Circle(radius) {
     this.radius = radius;
     this.radius = radius;
}
}


</syntaxhighlight><syntaxhighlight lang="javascript" class="mlw-continue">
</syntaxhighlight><syntaxhighlight lang="javascript" class="code-continue">
Circle.call({}, 1); // This expression is equal to 'new Circle(1)'
Circle.call({}, 1); // This expression is equal to 'new Circle(1)'
</syntaxhighlight><syntaxhighlight lang="javascript" class="mlw-continue">
</syntaxhighlight><syntaxhighlight lang="javascript" class="code-continue">
Circle.apply({}, [1]); // This expression is equal to 'new Circle(1)'
Circle.apply({}, [1]); // This expression is equal to 'new Circle(1)'
</syntaxhighlight>
</syntaxhighlight>
Line 220: Line 220:


When we work with primitives (value types) the value is stored inside the variable. This the primitives become independent.
When we work with primitives (value types) the value is stored inside the variable. This the primitives become independent.
<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 236: Line 236:
| size = 100%
| size = 100%
}}When we work with objects (reference types) the value is stored into an internal JavaScript object and the value of the object's ''variable'' is just a reference to that internal object.
}}When we work with objects (reference types) the value is stored into an internal JavaScript object and the value of the object's ''variable'' is just a reference to that internal object.
<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;
Line 250: Line 250:
'''Another ''Value vs Reference Types'' example'''
'''Another ''Value vs Reference Types'' example'''


<syntaxhighlight lang="javascript" class="mlw-continue">
<syntaxhighlight lang="javascript" class="code-continue">
let number = 10;
let number = 10;
function increase(number) {
function increase(number) {
Line 261: Line 261:
10
10
</syntaxhighlight>
</syntaxhighlight>
<syntaxhighlight lang="javascript" class="mlw-continue">
<syntaxhighlight lang="javascript" class="code-continue">
let obj = { value: 10};
let obj = { value: 10};
function increase(obj) {
function increase(obj) {
Line 274: Line 274:


== Adding or Removing Properties - DOT and BRACKET Notation ==
== Adding or Removing Properties - DOT and BRACKET Notation ==
The objects in JavaScript are dynamic, that means after creating them we can add properties (or methods) to them or delete some properties.<syntaxhighlight lang="javascript" class="mlw-continue">
The objects in JavaScript are dynamic, that means after creating them we can add properties (or methods) to them or delete some properties.<syntaxhighlight lang="javascript" class="code-continue">
function Circle(radius) {
function Circle(radius) {
     this.radius = radius;
     this.radius = radius;
Line 283: Line 283:
const circle = new Circle(1);
const circle = new Circle(1);


</syntaxhighlight>'''Add a property via DOT notation'''<syntaxhighlight lang="javascript" class="mlw-continue">
</syntaxhighlight>'''Add a property via DOT notation'''<syntaxhighlight lang="javascript" class="code-continue">
circle.location = {x: 1, y: 1};
circle.location = {x: 1, y: 1};


</syntaxhighlight><syntaxhighlight lang="javascript" class="mlw-continue">
</syntaxhighlight><syntaxhighlight lang="javascript" class="code-continue">
consloe.log(circle);
consloe.log(circle);


</syntaxhighlight><syntaxhighlight lang="shell-session">
</syntaxhighlight><syntaxhighlight lang="shell-session">
Circle {radius: 1, location: {x: 1, y: 1}, draw: ƒ}
Circle {radius: 1, location: {x: 1, y: 1}, draw: ƒ}
</syntaxhighlight>'''Add a property via BRACKET notation'''<syntaxhighlight lang="javascript" class="mlw-continue">
</syntaxhighlight>'''Add a property via BRACKET notation'''<syntaxhighlight lang="javascript" class="code-continue">
circle['visible'] = true;
circle['visible'] = true;


</syntaxhighlight><syntaxhighlight lang="javascript" class="mlw-continue">
</syntaxhighlight><syntaxhighlight lang="javascript" class="code-continue">
consloe.log(circle);
consloe.log(circle);


</syntaxhighlight><syntaxhighlight lang="shell-session">
</syntaxhighlight><syntaxhighlight lang="shell-session">
Circle {radius: 1, location: {x: 1, y: 1}, visible: true, draw: ƒ}
Circle {radius: 1, location: {x: 1, y: 1}, visible: true, draw: ƒ}
</syntaxhighlight>The Bracket notation is useful in some cases, especially when we pass the name of the property as value of a variable:<syntaxhighlight lang="javascript" class="mlw-continue">
</syntaxhighlight>The Bracket notation is useful in some cases, especially when we pass the name of the property as value of a variable:<syntaxhighlight lang="javascript" class="code-continue">
const propertyName = 'location';
const propertyName = 'location';
console.log(circle[propertyName]);
console.log(circle[propertyName]);
</syntaxhighlight><syntaxhighlight lang="shell-session">
</syntaxhighlight><syntaxhighlight lang="shell-session">
{x: 1, y: 1}
{x: 1, y: 1}
</syntaxhighlight>Another useful application of the Bracket notation is when we have special characters in the property name.<syntaxhighlight lang="javascript" class="mlw-continue">
</syntaxhighlight>Another useful application of the Bracket notation is when we have special characters in the property name.<syntaxhighlight lang="javascript" class="code-continue">
circle['center-location'] = {x: 1, y: 1};
circle['center-location'] = {x: 1, y: 1};
console.log(circle['center-location']);
console.log(circle['center-location']);
</syntaxhighlight><syntaxhighlight lang="shell-session">
</syntaxhighlight><syntaxhighlight lang="shell-session">
{x: 1, y: 1}
{x: 1, y: 1}
</syntaxhighlight>'''Delete a property of an Object'''<syntaxhighlight lang="javascript" class="mlw-continue">
</syntaxhighlight>'''Delete a property of an Object'''<syntaxhighlight lang="javascript" class="code-continue">
delete circle['center-location'];
delete circle['center-location'];
delete circle.location;
delete circle.location;
Line 315: Line 315:


== Enumerating Properties ==
== Enumerating Properties ==
<syntaxhighlight lang="javascript" class="mlw-continue">
<syntaxhighlight lang="javascript" class="code-continue">
function Circle(radius) {
function Circle(radius) {
     this.radius = radius;
     this.radius = radius;
Line 324: Line 324:
const circle = new Circle(10);
const circle = new Circle(10);


</syntaxhighlight>For iterating over the properties of an Object we can use the <code>for.. in..</code> loop that will loop over the Properties and the Methods of the object.<syntaxhighlight lang="javascript" class="mlw-continue">
</syntaxhighlight>For iterating over the properties of an Object we can use the <code>for.. in..</code> loop that will loop over the Properties and the Methods of the object.<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 334: Line 334:
draw ƒ () { console.log('draw'); }
draw ƒ () { console.log('draw'); }
</syntaxhighlight>
</syntaxhighlight>
In order to get only the Properties but not the Methods we can use the <code>typeof</code> operator within an <code>if</code> statement.<syntaxhighlight lang="javascript" class="mlw-continue">
In order to get only the Properties but not the Methods we can use the <code>typeof</code> operator within an <code>if</code> statement.<syntaxhighlight lang="javascript" class="code-continue">
for (let key in circle) {
for (let key in circle) {
     if (typeof circle[key] !== 'function')
     if (typeof circle[key] !== 'function')
Line 342: Line 342:
radius 10
radius 10
</syntaxhighlight>
</syntaxhighlight>
In order to get all the keys of an Object as an Array we can use the method <code>Object.keys(obj)</code>. With this approach we cannot separate the Properties and the Methods.<syntaxhighlight lang="javascript" class="mlw-continue">
In order to get all the keys of an Object as an Array we can use the method <code>Object.keys(obj)</code>. With this approach we cannot separate the Properties and the Methods.<syntaxhighlight lang="javascript" class="code-continue">
const keys = Object.keys(circle);
const keys = Object.keys(circle);
console.log(keys);
console.log(keys);
Line 348: Line 348:
(2) ['radius', 'draw']
(2) ['radius', 'draw']
</syntaxhighlight>
</syntaxhighlight>
In order to test whether an Object has a certain Property we can use <code>if.. in..</code> statement as follow.<syntaxhighlight lang="javascript" class="mlw-continue">
In order to test whether an Object has a certain Property we can use <code>if.. in..</code> statement as follow.<syntaxhighlight lang="javascript" class="code-continue">
if ('radius' in circle)
if ('radius' in circle)
     console.log('Circle has a radius.');
     console.log('Circle has a radius.');
Line 356: Line 356:


== Abstraction - Private Properties and Methods ==
== Abstraction - Private Properties and Methods ==
Abstraction means: '''Hide the details and complexity and show (or expose) only the essentials.'''<syntaxhighlight lang="javascript" class="mlw-continue">
Abstraction means: '''Hide the details and complexity and show (or expose) only the essentials.'''<syntaxhighlight lang="javascript" class="code-continue">
function Circle(radius) {
function Circle(radius) {
     this.radius = radius;
     this.radius = radius;
Line 372: Line 372:
const circle = new Circle(10);
const circle = new Circle(10);


</syntaxhighlight>In order to apply Abstraction and hide the <code>defaultLocation</code> property and <code>computeOptimumLocation</code> method we must rewrite our Constructor function in the following way where these members are defined as local variables (within the constrictor function's closure).<syntaxhighlight lang="javascript" class="mlw-continue">
</syntaxhighlight>In order to apply Abstraction and hide the <code>defaultLocation</code> property and <code>computeOptimumLocation</code> method we must rewrite our Constructor function in the following way where these members are defined as local variables (within the constrictor function's closure).<syntaxhighlight lang="javascript" class="code-continue">
function Circle(radius) {
function Circle(radius) {
     this.radius = radius;
     this.radius = radius;
Line 395: Line 395:




Here is how to get access to a private members of an object.<syntaxhighlight lang="javascript" class="mlw-continue">
Here is how to get access to a private members of an object.<syntaxhighlight lang="javascript" class="code-continue">
function Circle(radius) {
function Circle(radius) {
     this.radius = radius;
     this.radius = radius;
Line 406: Line 406:
const circle = new Circle(10);
const circle = new Circle(10);


</syntaxhighlight><syntaxhighlight lang="javascript" class="mlw-continue">
</syntaxhighlight><syntaxhighlight lang="javascript" class="code-continue">
console.log(circle.defaultLocation());
console.log(circle.defaultLocation());


</syntaxhighlight><syntaxhighlight lang="shell-session">
</syntaxhighlight><syntaxhighlight lang="shell-session">
{x: 0, y: 0}
{x: 0, y: 0}
</syntaxhighlight>In order to access the <code>defaultLocation</code> as property (not like a method as in the example above) we need to use ''Getter function''. Also we can us a Setter function in order to set values to a private properties. Here is how this could be implemented within our Constructor function.<syntaxhighlight lang="javascript" class="mlw-continue">
</syntaxhighlight>In order to access the <code>defaultLocation</code> as property (not like a method as in the example above) we need to use ''Getter function''. Also we can us a Setter function in order to set values to a private properties. Here is how this could be implemented within our Constructor function.<syntaxhighlight lang="javascript" class="code-continue">
function Circle(radius) {
function Circle(radius) {
     this.radius = radius;
     this.radius = radius;
Line 428: Line 428:
const circle = new Circle(10);
const circle = new Circle(10);


</syntaxhighlight><syntaxhighlight lang="javascript" class="mlw-continue">
</syntaxhighlight><syntaxhighlight lang="javascript" class="code-continue">
console.log(circle.defaultLocation);
console.log(circle.defaultLocation);


</syntaxhighlight><syntaxhighlight lang="shell-session">
</syntaxhighlight><syntaxhighlight lang="shell-session">
{x: 0, y: 0}
{x: 0, y: 0}
</syntaxhighlight><syntaxhighlight lang="javascript" class="mlw-continue">
</syntaxhighlight><syntaxhighlight lang="javascript" class="code-continue">
circle.defaultLocation = {x: 5, y: 6};
circle.defaultLocation = {x: 5, y: 6};
console.log(circle.defaultLocation);
console.log(circle.defaultLocation);

Latest revision as of 08:30, 26 September 2022

Ref­er­ences

See al­so:

Ob­ject Lit­er­als

const circle = {};

The Ob­jects are col­lec­tions of key: val­ue pears.

const circle = {
    radius: 1,                  // Property, Number
    location: {                 // Property, Object Literals      
        x: 1,                       // Property, Number
        y: 1                        // Property, Bumber
    },
    draw: function() {          // Method, a Function
        console.log('draw');
    }
};

The cir­cle ob­ject above has 3 mem­bers: 2 prop­er­ties (ra­dius and lo­ca­tion) and 1 method (draw). The prop­er­ties are used to hold val­ues. The meth­ods are used to hold log­ic. When an Ob­ject has one or more meth­ods we can say it has be­hav­ior. The syn­tax of method de­f­i­n­i­tion could be sim­pli­fied by re­mov­ing the func­tion key­word and the colon de­lim­iter.

const circle = {
    radius: 1,                  // Property, Number
    location: {                 // Property, Object Literals      
        x: 1,                       // Property, Number
        y: 1                        // Property, Bumber
    },
    draw() {          // Method, a Function
        console.log('draw');
    }
};
console.log(circle);
{radius: 1, location: {…}, draw: ƒ}

Fac­to­ries

The Fac­to­ry func­tions pro­duce Ob­jects. In the above ex­am­ple is used ES6 fea­ture where when the names of the key and the vari­able that will pro­duce the val­ue are iden­ti­cal, in­stead of prop­er­ty: prop­er­ty, we can write just prop­er­ty, with­in the ob­ject re­turned by the fac­to­ry func­tion.

function createCircle(radius, location) {
    return {
        radius,
        location,
        draw() {
            console.log('draw');
        }
    }
}
const circle1 = createCircle(1, {x: 1, y: 1});
const circle2 = createCircle(2, {x: 1, y: 1});
console.log(circle1, circle2);
{radius: 1, location: {…}, draw: ƒ} 
{radius: 2, location: {…}, draw: ƒ}

Con­struc­tors

Con­struc­tor func­tions are an­oth­er way to cre­ate an ob­ject. Un­like the Fac­to­ry func­tions which re­turn an ob­ject it­self, the Con­struc­tor func­tions are used with the new op­er­a­tor that cre­ates the new ob­ject.

function Circle(radius, location) {
    this.radius = radius;
    this.location = location;
    this.draw = function() {
        console.log('draw');
    }
}
const circle1 = new Circle(1, {x: 1, y: 1});
const circle2 = new Circle(1, {x: 1, y: 1});
console.log(circle1, circle2);
Circle {radius: 1, location: {…}, draw: ƒ}
Circle {radius: 2, location: {…}, draw: ƒ}

The Con­struc­tor func­tions are the base for prop­er un­der­stand­ing the ES6 Class­es. The ES6 Class­es will be dis­cussed in a sep­a­rate chap­ter, but let's see how the Class equiv­a­lent to the above Con­struc­tor func­tion looks like.

function Circle(radius, location) {
    this.radius = radius;
    this.location = location;
    this.draw = function() {
        console.log('draw');
    }
}
const circle1 = new Circle(1, {x: 1, y: 1});
const circle2 = new Circle(1, {x: 1, y: 1});
console.log(circle1, circle2);
Circle {radius: 1, location: {…}, draw: ƒ}
Circle {radius: 2, location: {…}, draw: ƒ}

Con­struc­tor Prop­er­ty

Every ob­ject in JavaScript has a prop­er­ty called Con­struc­tor. It ref­er­ences to the func­tion that was used to con­struct (or cre­ate) the ob­ject.

Ob­ject cre­at­ed by ES6 Class

class Circle {
    constructor(radius) {
        this.radius = radius;
    }
}
const circle = new Circle(1);
circle.constructor;
class Circle {
    constructor(radius) {
        this.radius = radius;
    }
}

Ob­ject cre­at­ed by Con­struc­tor func­tion

function Circle(radius) {
    this.radius = radius;
}
const circle = new Circle(1);
circle.constructor;
ƒ Circle(radius) {
    this.radius = radius;
}

Ob­ject cre­at­ed by Fac­to­ry func­tion

function createCircle(radius) {
    return { radius }
}
const circle = createCircle(1);
circle.constructor;
ƒ Object() { [native code] }

Ob­ject cre­at­ed by Ob­ject Lit­er­als

const circle = { radius: 1 };
circle.constructor;
ƒ Object() { [native code] }

Built-in Con­struc­tor func­tions in JavaScript

  • ƒ Ob­ject() => new Ob­ject(); {};
  • ƒ String() => new String('string'); 'string'; "string"; `string`;
  • ƒ Boolean() => new Boolean(true|false); true; false;
  • ƒ Num­ber() => new Number(1); 1; 2;
  • ƒ Func­tion() => new Function('arguments', `func­tion con­tent`) func­tion name(arguments) { func­tion con­tent };
  • ƒ Er­ror() => throw new Errot('the er­ror mes­sage');
  • etc.

Func­tions are Ob­jects

The Func­tions in JavaScript are ob­jects. And they have built-in meth­ods and prop­er­ties.

function Circle(radius) {
    this.radius = radius;
}
Circle.name;
'Circle'
Circle.length;  // return the number of the arguments
1
Circle.constructor
ƒ Function() { [native code] }

There is Con­struc­tor func­tion, called Func­tion(), that cre­ates the func­tions when we de­fine them in lit­er­als. So when we de­fine a func­tion in the fol­low­ing way.

function Circle(radius) {
    this.radius = radius;
}

In the back­ground the JavaScript en­gine does some­thing like this.

const Circle = new Function('radius', `this.radius = radius;`);
const circle = new Circle(1);
console.log(circle);
{radius: 1}

Function's Meth­ods – .call() and .ap­ply()

function Circle(radius) {
    this.radius = radius;
}
Circle.call({}, 1); // This expression is equal to 'new Circle(1)'
Circle.apply({}, [1]); // This expression is equal to 'new Circle(1)'

Val­ue vs Ref­er­ence Types

  • See al­so: JavaScript Ba­sics: Types
  • Val­ue types (Prim­i­tives) are copied by val­ue, Ref­er­ence types (Ob­jects) are copied by a ref­er­ence.

The Val­ue types (Prim­i­tives) in JavaScript are:

  1. Strings
  2. Num­bers
  3. Booleans
  4. un­de­fined
  5. null
  6. Sym­bol (ES6)

When we work with prim­i­tives (val­ue types) the val­ue is stored in­side the vari­able. This the prim­i­tives be­come in­de­pen­dent.

let x = 10;
let y = x;
x = 20;
console.log(x, y); // note the two variables will have different value
20 10

The Ref­er­ence types in JavaScript are – at all in JavaScript all Ref­er­ence types are Ob­jects:

  1. Ob­jects
  2. Ar­rays
  3. Func­tions

When we work with ob­jects (ref­er­ence types) the val­ue is stored in­to an in­ter­nal JavaScript ob­ject and the val­ue of the object's vari­able is just a ref­er­ence to that in­ter­nal ob­ject.

let x = {value: 10};
let y = x;
x.value = 20;
console.log(x.value, y.value); // note the two 'variables' will have the same value
20 20

When we copy x to y the ref­er­ence is copy not the val­ue, thus the two vari­ables (x and y) ref­er­enc­ing to the same JavaScript ob­ject in the mem­o­ry.

An­oth­er Val­ue vs Ref­er­ence Types ex­am­ple

let number = 10;
function increase(number) {
    number++;               // this 'number' Variable is complete independant of the number varible defined outside
}                           // So when we pass the 'number' variable as argument to the function its value
increase(number);           // is coppied to the internal variable. So the value of the global variable 'number'
console.log(number);        // is not touched by the function and we will see 10 on the console
10
let obj = { value: 10};
function increase(obj) {
    obj.value++;         // this 'obj' Object will have the same reference 
}                        // as the Object passed to the function as argument
increase(obj);           // So the value of the global Object 'obj'
console.log(obj);        // will be changed by the function and we will see 11 on the console
{value: 11}

Adding or Re­mov­ing Prop­er­ties – DOT and BRACK­ET No­ta­tion

The ob­jects in JavaScript are dy­nam­ic, that means af­ter cre­at­ing them we can add prop­er­ties (or meth­ods) to them or delete some prop­er­ties.

function Circle(radius) {
    this.radius = radius;
    this.draw = function() {
        console.log('draw');
    };
}
const circle = new Circle(1);

Add a prop­er­ty via DOT no­ta­tion

circle.location = {x: 1, y: 1};
consloe.log(circle);
Circle {radius: 1, location: {x: 1, y: 1}, draw: ƒ}

Add a prop­er­ty via BRACK­ET no­ta­tion

circle['visible'] = true;
consloe.log(circle);
Circle {radius: 1, location: {x: 1, y: 1}, visible: true, draw: ƒ}

The Brack­et no­ta­tion is use­ful in some cas­es, es­pe­cial­ly when we pass the name of the prop­er­ty as val­ue of a vari­able:

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

An­oth­er use­ful ap­pli­ca­tion of the Brack­et no­ta­tion is when we have spe­cial char­ac­ters in the prop­er­ty name.

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

Delete a prop­er­ty of an Ob­ject

delete circle['center-location'];
delete circle.location;

Enu­mer­at­ing Prop­er­ties

function Circle(radius) {
    this.radius = radius;
    this.draw = function() {
        console.log('draw');
    };
}
const circle = new Circle(10);

For it­er­at­ing over the prop­er­ties of an Ob­ject we can use the for.. in.. loop that will loop over the Prop­er­ties and the Meth­ods of the ob­ject.

for (let key in circle) {
    console.log(key, circle[key]);
    //          |    |-> Return the value of the key
    //          |-> Retyrn the key name
}
radius 10
draw ƒ () { console.log('draw'); }

In or­der to get on­ly the Prop­er­ties but not the Meth­ods we can use the type­of op­er­a­tor with­in an if state­ment.

for (let key in circle) {
    if (typeof circle[key] !== 'function')
        console.log(key, circle[key]);
}
radius 10

In or­der to get all the keys of an Ob­ject as an Ar­ray we can use the method Object.keys(obj). With this ap­proach we can­not sep­a­rate the Prop­er­ties and the Meth­ods.

const keys = Object.keys(circle);
console.log(keys);
(2) ['radius', 'draw']

In or­der to test whether an Ob­ject has a cer­tain Prop­er­ty we can use if.. in.. state­ment as fol­low.

if ('radius' in circle)
    console.log('Circle has a radius.');
Circle has a radius.

Ab­strac­tion – Pri­vate Prop­er­ties and Meth­ods

Ab­strac­tion means: Hide the de­tails and com­plex­i­ty and show (or ex­pose) on­ly the es­sen­tials.

function Circle(radius) {
    this.radius = radius;
    this.defaultLocation = {x: 0, y: 0};
    this.computeOptimumLocation = function(factor) {
      console.log('compute', factor);
    };
    this.draw = function() {
        this.computeOptimumLocation(0.1);
     // this.defaultLocation ...
     // this.radius ...
        console.log('draw');
    };
}
const circle = new Circle(10);

In or­der to ap­ply Ab­strac­tion and hide the de­fault­Lo­ca­tion prop­er­ty and com­puteOp­ti­mum­Lo­ca­tion method we must rewrite our Con­struc­tor func­tion in the fol­low­ing way where these mem­bers are de­fined as lo­cal vari­ables (with­in the con­stric­tor function's clo­sure).

function Circle(radius) {
    this.radius = radius;
    let defaultLocation = {x: 0, y: 0};
    let computeOptimumLocation = function(factor) {
      console.log('compute', factor);
    };
    this.draw = function() {
        computeOptimumLocation(0.1);
     // defaultLocation ...
     // this.radius ...
        console.log('draw');
    };
}
const circle = new Circle(10);

Get­ters and Set­ters


Here is how to get ac­cess to a pri­vate mem­bers of an ob­ject.

function Circle(radius) {
    this.radius = radius;
    let defaultLocation = {x: 0, y: 0};
    this.getDefaultLocation = function() {
        return defaultLocation;
        
    };
}
const circle = new Circle(10);
console.log(circle.defaultLocation());
{x: 0, y: 0}

In or­der to ac­cess the de­fault­Lo­ca­tion as prop­er­ty (not like a method as in the ex­am­ple above) we need to use Get­ter func­tion. Al­so we can us a Set­ter func­tion in or­der to set val­ues to a pri­vate prop­er­ties. Here is how this could be im­ple­ment­ed with­in our Con­struc­tor func­tion.

function Circle(radius) {
    this.radius = radius;
    let defaultLocation = {x: 0, y: 0};
    Object.defineProperty(this, 'defaultLocation', {
        get: function() {
            return defaultLocation;
        },
        set: function(value) {
            if (!value.x || !value.y)
                throw new Error('Invalid location property');
            defaultLocation = value;
        }
    });
}
const circle = new Circle(10);
console.log(circle.defaultLocation);
{x: 0, y: 0}
circle.defaultLocation = {x: 5, y: 6};
console.log(circle.defaultLocation);
{x: 5, y: 6}