JavaScript OOP Course 2: Objects Recap: Difference between revisions
m Стадий: 6 [Фаза:Утвърждаване, Статус:Утвърден]; Категория:JavaScript |
m Text replacement - "mlw-continue" to "code-continue" |
||
Line 10: | Line 10: | ||
== Object Literals == | == Object Literals == | ||
<syntaxhighlight lang="javascript" class=" | <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=" | </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=" | 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=" | </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=" | 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=" | </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=" | </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=" | 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=" | </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=" | </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=" | </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=" | </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=" | </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=" | '''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=" | </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=" | </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=" | </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=" | </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=" | </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=" | </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=" | </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=" | 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=" | </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=" | </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=" | </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=" | </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=" | </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=" | </syntaxhighlight><syntaxhighlight lang="javascript" class="code-continue"> | ||
const circle = new Circle(1); | const circle = new Circle(1); | ||
</syntaxhighlight><syntaxhighlight lang="javascript" class=" | </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=" | <syntaxhighlight lang="javascript" class="code-continue"> | ||
function Circle(radius) { | function Circle(radius) { | ||
this.radius = radius; | this.radius = radius; | ||
} | } | ||
</syntaxhighlight><syntaxhighlight lang="javascript" class=" | </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=" | </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=" | <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=" | <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=" | <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=" | <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=" | 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=" | </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=" | </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=" | </syntaxhighlight>'''Add a property via BRACKET notation'''<syntaxhighlight lang="javascript" class="code-continue"> | ||
circle['visible'] = true; | circle['visible'] = true; | ||
</syntaxhighlight><syntaxhighlight lang="javascript" class=" | </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=" | </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=" | </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=" | </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=" | <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=" | </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=" | 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=" | 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=" | 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=" | 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=" | </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=" | 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=" | </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=" | </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=" | </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=" | </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 07:30, 26 September 2022
References
- Code with Mosh: The Ultimate JavaScript Mastery Series – Part 2
- W3School: JavaScript Tutorial
See also:
Object Literals
const circle = {};
The Objects are collections of key:
value
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 circle
object above has 3 members: 2 properties (radius
and location
) and 1 method (draw
). 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.
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: ƒ}
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 property: property,
we can write just property
, within the object returned by the factory function.
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: ƒ}
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 new
operator that creates the new object.
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 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.
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: ƒ}
Constructor Property
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
class Circle {
constructor(radius) {
this.radius = radius;
}
}
const circle = new Circle(1);
circle.constructor;
class Circle {
constructor(radius) {
this.radius = radius;
}
}
Object created by Constructor function
function Circle(radius) {
this.radius = radius;
}
const circle = new Circle(1);
circle.constructor;
ƒ Circle(radius) {
this.radius = radius;
}
Object created by Factory function
function createCircle(radius) {
return { radius }
}
const circle = createCircle(1);
circle.constructor;
ƒ Object() { [native code] }
Object created by Object Literals
const circle = { radius: 1 };
circle.constructor;
ƒ Object() { [native code] }
Built-in Constructor functions in JavaScript
ƒ Object()
=>new Object();
{};
ƒ String()
=>new String('string');
'string';
"string";
`string`;
ƒ Boolean()
=>new Boolean(true|false);
true;
false;
ƒ Number()
=>new Number(1);
1;
2;
ƒ Function()
=>new Function('arguments', `function content`)
function name(arguments) { function content };
ƒ Error()
=>throw new Errot('the error message');
- etc.
Functions are Objects
The Functions in JavaScript are objects. And they have built-in methods and properties.
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 Constructor function, called Function()
, that creates the functions when we define them in literals. So when we define a function in the following way.
function Circle(radius) {
this.radius = radius;
}
In the background the JavaScript engine does something like this.
const Circle = new Function('radius', `this.radius = radius;`);
const circle = new Circle(1);
console.log(circle);
{radius: 1}
Function's Methods – .call()
and .apply()
- See also: JavaScript Functions: Changing
this
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)'
Value vs Reference Types
- See also: JavaScript Basics: Types
- Value types (Primitives) are copied by value, Reference types (Objects) are copied by a reference.
The Value types (Primitives) in JavaScript are:
- Strings
- Numbers
- Booleans
- undefined
- null
- Symbol (ES6)
When we work with primitives (value types) the value is stored inside the variable. This the primitives become independent.
let x = 10;
let y = x;
x = 20;
console.log(x, y); // note the two variables will have different value
20 10
The Reference types in JavaScript are – at all in JavaScript all Reference types are Objects:
- Objects
- Arrays
- Functions
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.
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 reference is copy not the value, thus the two variables (x
and y
) referencing to the same JavaScript object in the memory.
Another Value vs Reference Types example
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 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.
function Circle(radius) {
this.radius = radius;
this.draw = function() {
console.log('draw');
};
}
const circle = new Circle(1);
Add a property via DOT notation
circle.location = {x: 1, y: 1};
consloe.log(circle);
Circle {radius: 1, location: {x: 1, y: 1}, draw: ƒ}
Add a property via BRACKET notation
circle['visible'] = true;
consloe.log(circle);
Circle {radius: 1, location: {x: 1, y: 1}, visible: true, draw: ƒ}
The Bracket notation is useful in some cases, especially when we pass the name of the property as value of a variable:
const propertyName = 'location';
console.log(circle[propertyName]);
{x: 1, y: 1}
Another useful application of the Bracket notation is when we have special characters in the property name.
circle['center-location'] = {x: 1, y: 1};
console.log(circle['center-location']);
{x: 1, y: 1}
Delete a property of an Object
delete circle['center-location'];
delete circle.location;
Enumerating Properties
function Circle(radius) {
this.radius = radius;
this.draw = function() {
console.log('draw');
};
}
const circle = new Circle(10);
For iterating over the properties of an Object we can use the for.. in..
loop that will loop over the Properties and the Methods of the object.
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 order to get only the Properties but not the Methods we can use the typeof
operator within an if
statement.
for (let key in circle) {
if (typeof circle[key] !== 'function')
console.log(key, circle[key]);
}
radius 10
In order to get all the keys of an Object as an Array we can use the method Object.keys(obj)
. With this approach we cannot separate the Properties and the Methods.
const keys = Object.keys(circle);
console.log(keys);
(2) ['radius', 'draw']
In order to test whether an Object has a certain Property we can use if.. in..
statement as follow.
if ('radius' in circle)
console.log('Circle has a radius.');
Circle has a radius.
Abstraction – Private Properties and Methods
Abstraction means: Hide the details and complexity and show (or expose) only the essentials.
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 order to apply Abstraction and hide the defaultLocation
property and computeOptimumLocation
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).
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);
Getters and Setters
- See also: JavaScript Functions: Getter and Setters
Here is how to get access to a private members of an object.
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 order to access the defaultLocation
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.
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}