You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
In earlier JavaScript lectures we saw that we can define object literals and use functions to access and manipulate their properties. A typical example is shown below, where we have defined an array of objects, in this case each representing the name of a month and its associated number of days.
5
+
In earlier JavaScript lectures we saw that we can create objects through object literals and use functions to access and manipulate their properties. A typical example is shown below, where we have defined an array of objects, in this case each representing the name of a month and its associated number of days.
6
6
7
-
We're looping through the months and printing a message to the console for each month having 31 days.
7
+
We're looping through the months and printing an informational message to the console for each month having 31 days.
8
8
9
-
This style of programming is called Imperative Programming: we instruct the computer how to perform the task(s) at hand.
9
+
This style of programming is called Imperative Programming: in the code detail containing the `for` loop we instruct the computer _how to perform the task(s) at hand_.
10
10
11
11
```js
12
12
constmonths= [
@@ -33,13 +33,15 @@ for (const month of months) {
33
33
34
34
## Functional Programming
35
35
36
-
In the Functional Programming style (also referred to as Declarative Programming), we prefer to declare what the computer should do.
36
+
In the Functional Programming style (also referred to as Declarative Programming), we prefer to declare _what the computer should do_.
37
37
38
38
In the next example we have used the `filter` method to extract a subset of months having 31 days, used the `map` method to create an informational string for each month and a `forEach` method to output those strings to the console.
39
39
40
-
Or, put in other words, we state or **declare** that the computer should **filter** our array according to some predefined criterion, then **map** each filtered object to a string and print out each string to the console.
40
+
Put in other words, we state or **declare** that the computer should **filter** our array according to some predefined criterion, then **map** each filtered object to a string and print out each string to the console.
41
41
42
-
In contrast to the imperative style we do not have to infer from looking at the code what we are actually doing. Instead, the names of our functions and methods already imply what it is we want to achieve.
42
+
> A prime example of a declarative language is SQL, which you will learn in the HYF Database module.
43
+
44
+
In contrast to the Imperative Style we do not have to infer from looking at the code what is actually happening. Instead, the names of the functions and methods already indicate what it is we want to achieve.
43
45
44
46
```js
45
47
constmonths= [
@@ -63,7 +65,15 @@ months
63
65
.forEach(string=>console.log(string));
64
66
```
65
67
66
-
### Constructor Functions (pre-ES6)
68
+
### Constructor Functions (pre-ES6) and the `new` keyword
69
+
70
+
In the example below we use a function that is used in conjunction with the `new` keyword. Such a function is called a **constructor** function, and, by convention, we start its name with an uppercase letter.
71
+
72
+
When a function is called and preceded by the `new` keyword, something special happens. The JavaScript engine creates a new, empty object and assigns that object to the `this` variable.
73
+
74
+
> The `this` variable is always present in JavaScript. Its value is dependent on the current execution context. Most of the time, the value of `this` is `undefined`. However, when calling a method on an object, the `this` variable holds a reference to the object it is called on. We can use the `this` variable inside the method implementation to get at other properties and methods within the object.
75
+
76
+
We can now add properties to the new object through the `this` variable, as shown below.
67
77
68
78
```js
69
79
functionMonth(name, days) {
@@ -96,14 +106,30 @@ months
96
106
97
107
- StackOverflow: [What is the 'new' keyword in JavaScript?](https://stackoverflow.com/questions/1646698/what-is-the-new-keyword-in-javascript)
98
108
99
-
### ES6 Classes vs pre-ES6 Constructor Functions
109
+
### Introducing Object-Oriented Programming
110
+
111
+
In the preceding example, there was not much to be gained from using a constructor function in conjunction with the `new` keyword, as compared to just using object literals. The advantages become more clear when we start to add **methods** to the object. Methods are just plain JavaScript functions that you call on an object, using dot notation. In the code snippet below, we have defined a couple of functions and assigned them to object properties through the `this` variable in the constructor function. This makes these functions into methods.
100
112
101
113
```js
102
-
classMonth {
103
-
constructor(name, days) {
104
-
this.name= name;
105
-
this.days= days;
106
-
}
114
+
functionMonth(name, days) {
115
+
this.name= name;
116
+
this.days= days;
117
+
118
+
this.hasDays=function (days) {
119
+
returnthis.days=== days;
120
+
};
121
+
122
+
this.isLongMonth=function () {
123
+
returnthis.hasDays(31);
124
+
};
125
+
126
+
this.toString=function () {
127
+
return`${this.name} has ${this.days} days.`;
128
+
};
129
+
130
+
this.toConsole=function () {
131
+
console.log(this.toString());
132
+
};
107
133
}
108
134
109
135
constmonths= [
@@ -122,39 +148,47 @@ const months = [
122
148
];
123
149
124
150
months
125
-
.filter(month=>month.days===31)
126
-
.map(month=>`${month.name} has ${month.days} days.`)
127
-
.forEach(string=>console.log(string));
151
+
.filter(month=>month.isLongMonth())
152
+
.forEach(month=>month.toConsole());
128
153
```
129
154
130
-
### ES6 Classes and Object-Oriented Programming
155
+
We can now call these methods using dot notation, as in:
131
156
132
-
The remaining style of programming we will discuss here is called Object-Oriented Programming.
157
+
```js
158
+
month.isLongMonth()
159
+
month.toConsole()
160
+
```
161
+
162
+
We have already seen this notation when we used, for instance, `map` and `filter`.
163
+
164
+
When we add methods to an object to operate on data contained in the object, we have created a more or less self-contained object. The object knows how to operate its data and external code need not know anything about its internals. This concept is known as Object-Oriented Programming. It is the default style of programming in object-oriented languages such as Java, C# and C++. In JavaScript it is optional. In the HYF React module, ES6 classes are used extensively.
165
+
166
+
### Prototypes
133
167
134
-
TO BE CONTINUED
168
+
The code from the previous example has a significant inefficiency: each object get its own copy of the methods (`hasDays` etc). This takes up unnecessary memory. It would be far better if the objects could share a common set of methods. This is where JavaScript's concept of a `prototype` comes in.
169
+
170
+
Each JavaScript function has a `prototype` property that points to an, initially empty, prototype object. It only comes into play when using that function as a **constructor** function. We can assign functions to this prototype which are shared by all objects we create through calling the constructor function in combination with the `new` keyword.
135
171
136
172
```js
137
-
classMonth {
138
-
constructor(name, days) {
139
-
this.name= name;
140
-
this.days= days;
141
-
}
173
+
functionMonth(name, days) {
174
+
this.name= name;
175
+
this.days= days;
176
+
}
142
177
143
-
hasDays(days) {
144
-
returnthis.days=== days;
145
-
}
178
+
Month.prototype.hasDays=function(days) {
179
+
returnthis.days=== days;
180
+
};
146
181
147
-
isLongMonth() {
148
-
returnthis.hasDays(31);
149
-
}
182
+
Month.prototype.isLongMonth=function() {
183
+
returnthis.hasDays(31);
184
+
};
150
185
151
-
toString() {
152
-
return`${this.name} has ${this.days} days.`;
153
-
}
186
+
Month.prototype.toString=function() {
187
+
return`${this.name} has ${this.days} days.`;
188
+
};
154
189
155
-
toConsole() {
156
-
console.log(this.toString());
157
-
}
190
+
Month.prototype.toConsole=function () {
191
+
console.log(this.toString());
158
192
}
159
193
160
194
constmonths= [
@@ -177,32 +211,41 @@ months
177
211
.forEach(month=>month.toConsole());
178
212
```
179
213
180
-
### The Prototype Chain
214
+
215
+
The diagram below depicts how this sharing works out. At this time it is not necessary that you understand every detail. Just note how there is a single copy of functions, shared by all instances of the `Months` objects.
181
216
182
217

183
218
184
-
### Pre-ES6 Constructor Functions and Prototypes
219
+
### ES6 Classes
220
+
221
+
In ES6 a new way of defining objects and its methods was introduced. It uses the same `prototype` mechanism behind the scenes, but its syntax is closer to that of other object-oriented languages, such as Java, etc. Because it is only new syntax, hiding the intricacies of the `prototype`, it is often designated as 'syntactic sugaring'.
222
+
223
+
In ES6 classes we use the `class` keyword to define a class. The `constructor` method takes the place of the constructor function of the previous examples.
224
+
225
+
We define methods by creating functions inside the class body, however without the `function` keyword. As previously, the `this` keyword refers to the object that a method is called upon.
Now that we know a bit more about objects, prototypes and the `this` variable, it might be useful to revisit the `map` and `filter` methods we used before and examine how they might be implemented internally.
275
+
276
+
In the examples below, we have defined alternative implementations for `map` and `filter` and named them `myMap` and `myFilter`. If we run this code we are actually adding these methods to the existing `Array` constructor function (in general, it is a bad idea to modify standard JavaScript objects, but we use it here for illustrative purposes).
277
+
278
+
The `this` variable inside the method implementations refer to the array (which is technically an object: `typeof arr === 'object'`) on which the method is called.
279
+
280
+
As you can see, both methods use a `for` loop internally, saving us the trouble of writing a `for` loop ourselves. Both methods call a callback that was passed as a parameter. The callback, in its turn, is called for every loop iteration with three parameters, viz:
281
+
282
+
1. The current array element
283
+
2. The current loop index value
284
+
3. The complete array itself
285
+
286
+
For the `map` method, the value that we return from our callback is pushed onto a new, initially empty array.
287
+
288
+
For the `filter` method, the current element is pushed unmodified to a new, initially empty array if, and only if our callback returns a 'truthy' value.
289
+
290
+
Finally, both methods return the newly constructed array as their return value.
0 commit comments