Skip to content

Commit 1610b46

Browse files
committed
prototypes and inheritance
1 parent 225941c commit 1610b46

11 files changed

+205
-38
lines changed

.vscode/settings.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"cSpell.ignoreWords": [
3+
"iphone"
4+
]
5+
}

Assets/AmendedDateProto.png

43.3 KB
Loading

Assets/ArrayProto.png

102 KB
Loading

Assets/ArrayProtoProto.png

57.8 KB
Loading

Assets/Date.prototype.png

176 KB
Loading

Assets/Object.prototype.png

58.7 KB
Loading

Assets/PrototypalInheritance.png

837 KB
Loading

Assets/PrototypeProperty.png

79.3 KB
Loading

ClosuresPrototypalInheritance.md

Lines changed: 173 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ function something(fn) {
1717

1818
something(function() {
1919
console.log("hi");
20-
}); // => 'hi'
20+
}); // -> 'hi'
2121
```
2222

2323
- You can return functions as values from other functions.
@@ -29,7 +29,7 @@ function a() {
2929
};
3030
}
3131

32-
a()(); // => 'bye'
32+
a()(); // -> 'bye'
3333
```
3434
---
3535
## Higher Order Functions
@@ -60,22 +60,24 @@ function letUser(user, fn) {
6060
return giveAccessTo(user.name);
6161
}
6262

63-
letUser({level: 'general', name: 'Corey'}, authenticate); // => "Access granted to Corey"
63+
letUser({level: 'general', name: 'Corey'}, authenticate); // -> "Access granted to Corey"
6464
```
6565

6666
<i>Example:</i>
6767

6868
```javascript
6969
const multiplyBy = (num1) => (num2) => num1 * num2
7070

71-
multiplyBy(5)(3); // => 15
71+
multiplyBy(5)(3); // -> 15
7272

7373
const multiplyByTwo = multiplyBy(2);
74-
multiplyByTwo(5); // => 10
74+
multiplyByTwo(5); // -> 10
7575
```
7676
---
7777
## Closures
7878

79+
Closures allow a function to access variables from an enclosing scope or outer scope environment even after it leaves the scope in which it was declared because all that matters in Javascript is where the function was written.
80+
7981
![Closures](./Assets/Closures.png)
8082

8183
We have these things called closures in JavaScript because of two things that we get. One is the fact that in JavaScript functions are a first class citizen, we can pass them around like data of any other type.
@@ -98,7 +100,7 @@ function a() {
98100
}
99101
}
100102

101-
a()()() // => "John Simon Luke"
103+
a()()() // -> "John Simon Luke"
102104
```
103105

104106
Closure is a feature of JavaScript where the JavaScript engine will make sure that the function has access to all of the variables contained in other functions in which it's nested in.
@@ -108,7 +110,7 @@ Closure is a feature of JavaScript where the JavaScript engine will make sure th
108110
```javascript
109111
const family = (grandpa) => (father) => (son) => `${grandpa} ${father} ${son}`
110112

111-
family('John')('Simon')('Luke') // => "John Simon Luke"
113+
family('John')('Simon')('Luke') // -> "John Simon Luke"
112114
```
113115

114116
## Two main benefits of closures:
@@ -128,7 +130,7 @@ heavyDuty(426);
128130
heavyDuty(2094);
129131
heavyDuty(3421);
130132

131-
// =>
133+
// ->
132134
// func ran
133135
// func ran
134136
// func ran
@@ -152,7 +154,7 @@ getHeavyDuty(745);
152154
getHeavyDuty(2734);
153155
getHeavyDuty(4711);
154156

155-
// =>
157+
// ->
156158
// func ran
157159
// hi
158160
```
@@ -183,12 +185,172 @@ const makeNuclearButton = () => {
183185

184186
const tryDetonate = makeNuclearButton();
185187

186-
tryDetonate.launch(); // => won't work, can't access due to encapsulation
188+
tryDetonate.launch(); // -> won't work, can't access due to encapsulation
187189

188-
tryDetonate.totalPeaceTime(); // => does work, will print elapsed time
190+
tryDetonate.totalPeaceTime(); // -> does work, will print elapsed time
189191
```
190192

191193
Data encapsulation in relation to closures refers to the idea of removing access to certain data which shouldn't be accessible to a user. In the example above the user is able to interact with the `totalPeaceTime` function but they can't access the `launch` function. This is because the `launch` function is not being returned in the scoped `makeNuclearButton` function.
192194

195+
<br>
196+
197+
---
198+
## Prototypal Inheritance
199+
200+
Inheritance is when an object gets access to the properties and methods of another object.
201+
202+
#### Why is prototypal inheritance useful?
203+
204+
The fact that objects can share prototypes means that you can have objects with properties that are pointing to the same place in memory without the need to repeat code, thus being more efficient.
205+
206+
![Prototypal Inheritance](./Assets/PrototypalInheritance.png)
207+
208+
The chains in this diagram represent prototypal inheritance. Arrays and functions in JavaScript get access to the methods and properties of objects.
209+
210+
![array.__proto__](./Assets/ArrayProto.png)
211+
212+
Here we created an array, and by appending `.__proto__` we can go up the prototype chain and view the array constructor.
213+
214+
![array.__proto__](./Assets/ArrayProtoProto.png)
193215

216+
By appending another `.__proto__` we can go up the chain another level and view the object constructor.
217+
218+
---
219+
<br>
220+
221+
### Manually creating a prototype chain
222+
223+
#### Note: You should never use `__proto__` to manually assign the prototype chain yourself (like in this example). It will conflict with the compiler and cause performance issues. The purpose of this is to simply explain how it works.
224+
225+
<i>Example:</i>
226+
227+
```javascript
228+
let dragon = {
229+
name: 'Fred',
230+
fire: true,
231+
fight() {
232+
return 5
233+
},
234+
roar(){
235+
if (this.fire) {
236+
return `I am ${this.name}, the breather of fire.`
237+
}
238+
}
239+
}
240+
241+
let lizard = {
242+
name: 'Larry',
243+
fight() {
244+
return 1
245+
}
246+
}
247+
248+
lizard.__proto__ = dragon;
249+
250+
lizard.roar() // -> "I am Larry, the breather of fire"
251+
lizard.fire // -> true
252+
lizard.fight() // -> 1
253+
254+
dragon.isPrototypeOf(lizard) // -> true
255+
```
256+
257+
Here lizard is inheriting all the properties and methods of dragon through a prototype chain and is then overriding some attributes in it's own object declaration.
258+
259+
```javascript
260+
for (let prop in lizard) {
261+
console.log(prop) // -> name, fight, fire, roar
262+
}
263+
```
264+
265+
Here we're looping through all of lizard's properties and logging them out.
266+
267+
```javascript
268+
for (let prop in lizard) {
269+
if (lizard.hasOwnProperty(prop)) {
270+
console.log(prop) // -> name, fight
271+
}
272+
}
273+
```
274+
275+
Here we're looping through all of lizard's properties, filtering them with the `hasOwnProperty()` method and logging out only it's own (non-inherited) properties.
276+
277+
---
278+
<br>
279+
280+
### Inheritance using `Object.create()`
281+
282+
<i>Example:</i>
283+
284+
```javascript
285+
let iphone11 = {
286+
wirelessCharging: true
287+
}
288+
289+
let iphone11Pro = Object.create(iphone11)
290+
291+
iphone11Pro.wirelessCharging // -> true
292+
```
293+
294+
Here we're creating inheritance using `Object.create()`
295+
296+
---
297+
<br>
298+
299+
### Only functions have the `.prototype` property
300+
301+
![.prototype property](./Assets/PrototypeProperty.png)
302+
303+
Every function has a prototype property and it references to an object used to attach properties that will be inherited by objects further down the prototype chain.
304+
305+
The last object in the chain is this built in `Object.prototype`.
306+
307+
![Object.prototype](./Assets/Object.prototype.png)
308+
309+
`Object` is a function because it has the prototype property. The `Object.prototype` is what we call the base object. That's the very last piece or the very last object that we can look for properties on before we point to null.
310+
311+
---
312+
<br>
313+
314+
### Exercise:
315+
#### Extend the functionality of the built-in `Date` object by creating your own method which prints the previous year of a given date.
316+
317+
![Date.prototype](./Assets/Date.prototype.png)
318+
319+
These are all the built-in methods we can use with the `Date` object.
320+
321+
<i>Solution:</i>
322+
323+
```javascript
324+
Date.prototype.lastYear = function() {
325+
return this.getFullYear() - 1;
326+
}
327+
328+
new Date().lastYear() // -> 2018
329+
```
330+
331+
![Amended Date.prototype](./Assets/AmendedDateProto.png)
332+
333+
Now if we run `Date.prototype` we see our new function appears in the list of methods.
334+
335+
---
336+
<br>
337+
338+
339+
### Exercise:
340+
#### Extend the functionality of the built-in `Array` object by creating your own method which appends an exclamation mark to each value of an array.
341+
342+
<i>Solution:</i>
343+
344+
```javascript
345+
Array.prototype.emphasise = function() {
346+
let arr = [];
347+
for( let i = 0; i < this.length; i++ ) {
348+
arr.push((this[i] + '!'))
349+
}
350+
return arr
351+
}
352+
353+
[1,2,3].emphasise() // -> ["1!", "2!", "3!"]
354+
```
194355

356+
<i>Note: You can't use arrow functions in these solutions because the value of `this` would be lexically scoped to point to the function itself. We need to use a function expression because we want the value of `this` instead to be determined at call time when we actually run the function.</i>

Foundations.md

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ function jsengine(code) {
2727
}
2828

2929
jsengine("const x = 100");
30-
// => ['const', 'x', '=', '100']
30+
// -> ['const', 'x', '=', '100']
3131
```
3232

3333
---
@@ -355,9 +355,9 @@ const hello = function name() {
355355
return "Hey Corey";
356356
};
357357

358-
hello(); // => Hey Corey
358+
hello(); // -> Hey Corey
359359

360-
name(); // => Reference error
360+
name(); // -> Reference error
361361

362362
// name() only exists within the function scope of hello()
363363
```
@@ -395,9 +395,9 @@ const object = {
395395
}
396396
};
397397

398-
object.greet(); // => 'hello Corey'
398+
object.greet(); // -> 'hello Corey'
399399

400-
object.welcome(); // => 'Hello Corey, have a nice day!'
400+
object.welcome(); // -> 'Hello Corey, have a nice day!'
401401
```
402402

403403
- It provides the ability to execute the same code for multiple objects
@@ -421,9 +421,9 @@ const object2 = {
421421
startCar: startCar
422422
};
423423

424-
startCar(); // => "The Ford is running" (The global window is running the function)
424+
startCar(); // -> "The Ford is running" (The global window is running the function)
425425

426-
object1.startCar(); // => "The Audi is running" (The object is running the function)
426+
object1.startCar(); // -> "The Audi is running" (The object is running the function)
427427
```
428428

429429
---
@@ -450,11 +450,11 @@ const truck = {
450450
fuel: 20
451451
};
452452

453-
truck.fuel; // => 20
453+
truck.fuel; // -> 20
454454

455455
bus.reFuel.call(truck, 100, 40);
456456

457-
truck.fuel; // => 160
457+
truck.fuel; // -> 160
458458
```
459459

460460
#### `apply()`
@@ -465,7 +465,7 @@ For `.apply()` to work, arguments 1 and 2 need to be entered as an array:
465465
```javascript
466466
bus.reFuel.apply(truck, [100, 40]);
467467

468-
truck.fuel; // => 160
468+
truck.fuel; // -> 160
469469
```
470470

471471
#### `.bind()`
@@ -477,11 +477,11 @@ truck.fuel; // => 160
477477
```javascript
478478
const refuelTruck = bus.reFuel.bind(truck, 100, 40);
479479

480-
truck.fuel; // => 20
480+
truck.fuel; // -> 20
481481

482482
refuelTruck();
483483

484-
truck.fuel; // => 160
484+
truck.fuel; // -> 160
485485
```
486486

487487
<i>Summary:</i>
@@ -501,7 +501,7 @@ function multiply(a, b) {
501501

502502
let multiplyByTwo = multiply.bind(this, 2);
503503

504-
multiplyByTwo(4); // => 8
504+
multiplyByTwo(4); // -> 8
505505
```
506506

507507
---

0 commit comments

Comments
 (0)