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
Copy file name to clipboardExpand all lines: ObjectOrientedProgramming.md
+208-1Lines changed: 208 additions & 1 deletion
Original file line number
Diff line number
Diff line change
@@ -269,4 +269,211 @@ function sayAge() {
269
269
}
270
270
271
271
sayAge() // -> my age is 26
272
-
```
272
+
```
273
+
274
+
---
275
+
<br>
276
+
277
+
## Inheritance
278
+
279
+
Here we're going to create a base (super) class of Character and then create a sub class of Elf which will extend Character, inheriting it's properties. Elf will now have a prototype of Character.
280
+
281
+
The constructor within the Elf class exists only within Elf. If we want to set any properties within this constructor using the `this` keyword, we have to use the `super` keyword to call the superclass first. In doing so `super` will run the constructor and give us an instance of the Character base class. The `this` keyword will now refer to that instance, and we can now add on additional properties for the Elf subclass.
282
+
283
+
```javascript
284
+
classCharacter {
285
+
constructor(name, weapon) {
286
+
this.name= name;
287
+
this.weapon= weapon;
288
+
}
289
+
attack() {
290
+
return'attack with '+this.weapon;
291
+
}
292
+
}
293
+
294
+
classElfextendsCharacter {
295
+
constructor(name, weapon, type) {
296
+
super(name, weapon);
297
+
this.type= type;
298
+
}
299
+
}
300
+
301
+
classOgreextendsCharacter {
302
+
constructor(name, weapon, colour) {
303
+
super(name, weapon);
304
+
this.colour= colour;
305
+
}
306
+
makeFort() {
307
+
return'Strong fort made';
308
+
}
309
+
}
310
+
311
+
constdobby=newElf('dobby', 'cloth', 'house');
312
+
313
+
constshrek=newOgre('shrek', 'club', 'green');
314
+
shrek.makeFort() // -> Strong fort made
315
+
```
316
+
317
+
---
318
+
<br>
319
+
320
+
## Public & Private - Protected properties and methods
In object-oriented programming, properties and methods are split into two groups:
327
+
328
+
<b>Internal interface</b> – Methods and properties are accessible from other methods of the class, but not from the outside.
329
+
330
+
<b>External interface</b> – Methods and properties are accessible also from outside the class.
331
+
332
+
In JavaScript, there are two types of object fields (properties and methods):
333
+
334
+
<b>Public:</b> accessible from anywhere. They comprise the external interface. Till now we were only using public properties and methods.
335
+
336
+
<b>Private:</b> accessible only from inside the class. These are for the internal interface.
337
+
338
+
<br>
339
+
340
+
#### <i>Example:</i> Let's make a coffee machine
341
+
342
+
```javascript
343
+
classCoffeeMachine {
344
+
waterAmount =0;
345
+
346
+
constructor(power) {
347
+
this.power= power;
348
+
console.log(`Created a coffee machine. Power: ${power}.`)
349
+
}
350
+
}
351
+
352
+
constnespresso=newCoffeeMachine(100);
353
+
// -> Created a coffee machine. Power: 100.
354
+
355
+
nespresso.waterAmount=200;
356
+
```
357
+
358
+
#### Protected properties
359
+
360
+
Now let’s make the `waterAmount` property protected so we have more control over it. For instance, we don’t want anyone to set it below zero.
361
+
362
+
Protected properties are usually prefixed with an underscore `_`.
363
+
364
+
```javascript
365
+
classCoffeeMachine {
366
+
_waterAmount =0;
367
+
368
+
setwaterAmount(value) {
369
+
if (value <0) thrownewError('Negative water');
370
+
this._waterAmount= value;
371
+
}
372
+
373
+
getwaterAmount() {
374
+
returnthis._waterAmount;
375
+
}
376
+
377
+
constructor(power) {
378
+
this.power= power;
379
+
console.log(`Created a coffee machine. Power: ${power}.`)
380
+
}
381
+
}
382
+
383
+
constnespresso=newCoffeeMachine(100);
384
+
// -> Created a coffee machine. Power: 100.
385
+
386
+
nespresso.waterAmount=-50; // -> Uncaught Error: Negative water
387
+
```
388
+
389
+
#### Read-only properties
390
+
391
+
Let’s make the `power` property read-only.
392
+
393
+
Some properties will be set at creation time and never modified. That’s exactly the case for a coffee machine: power never changes.
394
+
395
+
To do so, we only need to make getter, but not the setter:
396
+
397
+
```javascript
398
+
classCoffeeMachine {
399
+
_waterAmount =0;
400
+
401
+
setwaterAmount(value) {
402
+
if (value <0) thrownewError('Negative water');
403
+
this._waterAmount= value;
404
+
}
405
+
406
+
getwaterAmount() {
407
+
returnthis._waterAmount;
408
+
}
409
+
410
+
constructor(power) {
411
+
this._power= power;
412
+
}
413
+
414
+
getpower() {
415
+
returnthis._power;
416
+
}
417
+
}
418
+
419
+
constnespresso=newCoffeeMachine(100);
420
+
421
+
console.log(`Power is: ${nespresso.power}W`); // -> Power is 100W
422
+
423
+
nespresso.power=250; // -> Error (no setter)
424
+
```
425
+
426
+
#### Private properties
427
+
428
+
<i>Note: Not yet universally supported.</i>
429
+
430
+
There’s a finished JavaScript proposal, almost in the standard, that provides language-level support for private properties and methods.
431
+
432
+
Privates should start with `#`. They are only accessible from inside the class.
433
+
434
+
For instance, here’s a private `#waterLimit` property and the water-checking private method `#checkWater`:
435
+
436
+
```javascript
437
+
classCoffeeMachine {
438
+
#waterLimit =200;
439
+
440
+
#checkWater(value) {
441
+
if (value <0) thrownewError("Negative water");
442
+
if (value >this.#waterLimit) thrownewError("Too much water");
443
+
}
444
+
445
+
}
446
+
447
+
let nespresso =newCoffeeMachine();
448
+
449
+
// can't access privates from outside of the class
450
+
nespresso.#checkWater(); // Error
451
+
nespresso.#waterLimit =1000; // Error
452
+
```
453
+
454
+
On the language level, `#` is a special sign that the field is private. We can’t access it from outside or from inheriting classes.
455
+
456
+
Private fields do not conflict with public ones. We can have both private `#waterAmount` and public`#waterAmount` fields at the same time.
457
+
458
+
```javascript
459
+
classCoffeeMachine {
460
+
461
+
#waterAmount =0;
462
+
463
+
getwaterAmount() {
464
+
returnthis.#waterAmount;
465
+
}
466
+
467
+
setwaterAmount(value) {
468
+
if (value <0) thrownewError("Negative water");
469
+
this.#waterAmount = value;
470
+
}
471
+
}
472
+
473
+
let machine =newCoffeeMachine();
474
+
475
+
machine.waterAmount=100;
476
+
alert(machine.#waterAmount); // Error
477
+
```
478
+
479
+
Unlike protected ones, private fields are enforced by the language itself. That’s a good thing. But if we inherit from `CoffeeMachine`, then we’ll have no direct access to `#waterAmount`. We’ll need to rely on `waterAmount` getter/setter. In many scenarios such limitation is too severe. If we extend a `CoffeeMachine`, we may have legitimate reason to access its internals. That’s why protected fields are used more often, even though they are not supported by the language syntax.
0 commit comments