Skip to content

Commit 00be6c4

Browse files
#2 - typescript
1 parent 11fc6eb commit 00be6c4

File tree

1 file changed

+397
-0
lines changed

1 file changed

+397
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,397 @@
1+
/* { retosparaprogramadores } #2 FUNCIONES Y ALCANCE */
2+
// I use the book "Eloquent JavaScript: A Modern Introduction to Programming" by Marijn Haverbeke for concept reference.
3+
// I also use the book "Secrets of the JavaScript Ninja" by John Resig, Bear Bibeault, and Josip Maras.
4+
// I refer to "JavaScript Notes for Professionals" from the people of Stack Overflow. https://goalkicker.com/JavaScriptBook
5+
// Additionally, I use GPT as a reference and sometimes to correct or generate proper comments.
6+
//https://www.typescriptlang.org/docs/
7+
8+
// Short for log
9+
const log = console.log;
10+
11+
12+
/* FUNCTIONS */
13+
/* Functions are fundamental in TypeScript and JavaScript programming. They allow us to structure larger programs, reduce repetition,
14+
associate names with subprograms, and isolate these subprograms from each other.
15+
Functions can be used to calculate values, perform side effects, achieve code reuse, and enhance code readability. */
16+
17+
// Functions as first-class objects
18+
/* Functions in TypeScript are treated as first-class objects, meaning they can be assigned to variables,
19+
passed as arguments, and returned from other functions. */
20+
21+
// Created via literals.
22+
function addPad(number: number, width: number, pad: number | string = 0): string {
23+
let result = String(number);
24+
while (result.length < width) {
25+
result = `${pad}` + result;
26+
}
27+
return result;
28+
}
29+
30+
log(addPad(4, 3, '#')); // ##4
31+
log(addPad(56, 3, '$')); // $56
32+
log(addPad(7, 3)); // 007
33+
34+
// Note: Default arguments can be passed as shown in the last example.
35+
36+
// Assigned to variables, array entries, and properties of other objects
37+
const square = (n: number): number => n * n;
38+
39+
const funcArray: number[] = [];
40+
funcArray.push(square(8)); // Adds a new function to an array
41+
log(funcArray); // [64]
42+
43+
const data: { book_name: string; some_method?: () => void } = { book_name: 'Hackbook' };
44+
data.some_method = function () {
45+
console.log(`${data.book_name} is now available in z-lib.org, so hack the world.`);
46+
}; // Assigns a new function as a property of another object
47+
data.some_method(); // Hackbook is now available in z-lib.org, so hack the world.
48+
49+
// A newly created object passed as an argument to a function
50+
51+
// Passed as arguments to other functions (callbacks)
52+
function call(doSomething: () => void): void {
53+
doSomething();
54+
}
55+
56+
call(() => log('Hi roadmap coders!')); // Hi roadmap coders!
57+
58+
// Returned as values from functions
59+
function returnFunc(): (str: string) => void {
60+
return function (str: string) { console.log(str); };
61+
}
62+
63+
const greeting = returnFunc();
64+
greeting('Hi there!'); // Hi there!
65+
66+
// Functions can possess properties that can be dynamically created and assigned like objects:
67+
const callMom = function () { log('Mommmmm!'); };
68+
69+
callMom(); // Mommmmm!
70+
callMom.name = "Mom";
71+
log(callMom.name); // Logs: callMom because "name" is an inherited property of the function constructor and is not writable
72+
73+
callMom.something = 'something';
74+
log(callMom.something); // something
75+
76+
log(callMom); /* Logs:
77+
[Function: callMom] { something: 'something' } */
78+
79+
/* Functions are objects with the special capability of being invokable. */
80+
81+
// Constructor functions are functions designed to construct a new object.
82+
function Cat(this: any, name: string, color: string, sound: string) {
83+
this.name = name;
84+
this.color = color;
85+
this.sound = sound;
86+
}
87+
88+
// Constructor functions are invoked using the new keyword:
89+
const psicoCat = new Cat("Psicotrogato", "Black & White", "Meaw");
90+
log(psicoCat.color); // Black & White
91+
psicoCat.sound = "Hey girl what's your name, what's your name?... I forgot";
92+
93+
// Constructor functions also have a prototype property which points to an object whose properties are automatically inherited by all objects created with that constructor:
94+
Cat.prototype.speak = function () {
95+
log(this.sound);
96+
};
97+
98+
psicoCat.speak(); // "Hey girl what's your name, what's your name?.. I forgot"
99+
100+
// Closure
101+
/* The ability to treat functions as values, combined with the fact that local bindings are recreated every time a function is called,
102+
leads to interesting possibilities. */
103+
104+
const incrementer = (function (n: number) {
105+
let local = n;
106+
return () => local++;
107+
})(0); // Immediately invoked with an initial value of 0
108+
109+
console.log('incrementer value is:', incrementer()); // incrementer value is: 0
110+
console.log('incrementer value is:', incrementer()); // incrementer value is: 1
111+
console.log('incrementer value is:', incrementer()); // incrementer value is: 2
112+
113+
// In the previous example, we used an IIFE (Immediately Invoked Function Expression) to create a closure,
114+
// but we can achieve the same with regular functions.
115+
function square_v2(n: number): () => number {
116+
return () => n * n;
117+
}
118+
119+
const pow64 = square_v2(64);
120+
const pow78 = square_v2(78);
121+
122+
log(pow64()); // 4096
123+
log(pow78()); // 6084
124+
125+
// Arrow Functions
126+
const factor = (n: number): number => {
127+
if (n === 1) return 1;
128+
return n * factor(n - 1);
129+
};
130+
131+
log(factor(8)); // 40320
132+
133+
// Note: The factor function is recursive, meaning it calls itself.
134+
135+
// Arrow functions allow us to abbreviate expressions when they have only one parameter or a single expression.
136+
const square_v3 = (n: number): number => n * n;
137+
log(square_v3(4)); // 16
138+
// Note: We omit the curly braces, the return statement, and also the parentheses.
139+
140+
// Note 2: It's important to remember that arrow functions do not have their
141+
// The following code is commented to avoid conflicts in Node.js environments.
142+
// If you transpile it to JavaScript, it will run fine in a browser.
143+
//own 'this' context.
144+
// const obj = {
145+
// value: 'Rutadeprogramacion Exercice #2.',
146+
// advertisement: function () {
147+
// log(this.value); // Rutadeprogramacion Exercice #2
148+
// setTimeout(() => {
149+
// alert(`${this.value} Please open the Browser Developer Tools.`);
150+
// }, 1000);
151+
// }
152+
// };
153+
154+
//obj.advertisement(); // Alert: Rutadeprogramacion Exercice #2. Please open the Browser Developer Tools. and Logs in console: Rutadeprogramacion Exercice #2.
155+
156+
/* Note: Because arrow functions don't have `this`, the 'this' points to obj.
157+
If we had used a regular function instead of the arrow function inside the setTimeout,
158+
it would have alerted undefined or thrown a reference error. */
159+
160+
// Function Declarations: A function declaration defines a named function. It is hoisted, meaning it can be called before it is defined in the code.
161+
function subtract(n: number, m: number): number {
162+
return n - m;
163+
}
164+
165+
log(subtract(8, 4)); // 4
166+
167+
// Function Expressions: A function expression defines a function as part of a larger expression.
168+
// It can be anonymous or named and is not hoisted.
169+
const multiply = function (n: number, m: number): number {
170+
return n * m;
171+
};
172+
173+
log(multiply(8, 9)); // 72
174+
175+
const add = function add(a: number, b: number): number {
176+
return a + b;
177+
}; // Can share the name for the binding word & the named function
178+
179+
log(add(3, 3)); // 6
180+
181+
// Arrow Functions: Introduced in ES6, arrow functions provide a more concise syntax for writing functions.
182+
const divide = (n: number, m: number): number => n / m;
183+
184+
log(divide(543, 56)); // 9.696428571428571
185+
186+
// Anonymous Functions: These are functions that do not have a name.
187+
// They are often used in callbacks or as arguments to other functions.
188+
// The following code is commented to avoid conflicts in Node.js environments.
189+
// If you transpile it to JavaScript, it will run fine in a browser.
190+
// window.addEventListener('load', function () {
191+
// const body = document.querySelector('body') as HTMLBodyElement;
192+
// const title = document.createElement('h1');
193+
194+
// body.style.setProperty('background', '#000');
195+
// body.style.setProperty('text-align', 'center');
196+
197+
// title.textContent = 'Retosparaprogramadores #2.';
198+
// title.style.setProperty('font-size', '3.5vmax');
199+
// title.style.setProperty('color', '#fff');
200+
// title.style.setProperty('line-height', '100vh');
201+
202+
// body.appendChild(title);
203+
204+
// log('This is an anonymous function'); // This will be logged at the end due to the nature of the window event
205+
// });
206+
207+
let sayHi = function () {
208+
console.log('Hi');
209+
};
210+
211+
sayHi(); // Hi
212+
213+
/* Named functions differ from anonymous functions in multiple scenarios:
214+
- When debugging, the name of the function will appear in the error/stack trace.
215+
- Named functions are hoisted while anonymous functions are not.
216+
- Named functions and anonymous functions behave differently when handling recursion.
217+
- Depending on the ECMAScript version, named and anonymous functions may treat the function name property differently. */
218+
219+
// Immediately Invoked Function Expressions (IIFE): An IIFE is a function that is executed immediately after it is defined.
220+
// It is often used to create a new scope and avoid scope pollution.
221+
let iife = (function () {
222+
console.log("This is another example of IIFE functions"); // This will be logged
223+
})();
224+
225+
/* Higher-Order Functions: These are functions that take other functions as arguments or return functions as their result.
226+
They are commonly used in functional programming. */
227+
228+
// Example of a sum function
229+
function sum(numbers: number[]): number {
230+
let total = 0;
231+
for (let i = 0; i < numbers.length; i++) {
232+
total += numbers[i];
233+
}
234+
return total;
235+
}
236+
237+
// Example of a range function
238+
function range(n: number, m: number): number[] {
239+
let result: number[] = [];
240+
for (let i = n; i <= m; i++) {
241+
result.push(i);
242+
}
243+
return result;
244+
}
245+
246+
// Using the sum and range functions together
247+
log(sum(range(1, 100))); // 5050
248+
249+
/* Generator Functions: Introduced in ES6, generator functions can pause and resume execution.
250+
They are defined using the function * syntax and use the yield keyword. */
251+
function* IdGenerator() {
252+
let id = 0;
253+
while (true) {
254+
yield addPad(++id, 5);
255+
}
256+
}
257+
258+
const idIterator = IdGenerator();
259+
260+
log(idIterator.next().value); // 00001
261+
log(idIterator.next().value); // 00002
262+
263+
/* Async Functions: Async functions are a way to work with asynchronous code.
264+
They return a promise and can use the await keyword to pause execution until a promise is resolved. */
265+
266+
// Note: You may need an extension to allow CORS (Cross-Origin Resource Sharing) to avoid console warnings.
267+
const getLoremIpsum = (numberOfParagraphs: number): Promise<string[]> => {
268+
return fetch(`https://baconipsum.com/api/?type=meat-and-filler&paras=${numberOfParagraphs}`)
269+
.then(response => response.json())
270+
.then(loremIpsumTextArray => {
271+
return loremIpsumTextArray;
272+
})
273+
.catch(error => {
274+
showError(error);
275+
});
276+
};
277+
278+
const showError = (error: any): void => console.log(error);
279+
280+
async function logParagraphs(): Promise<void> {
281+
const result = await getLoremIpsum(2);
282+
console.log(result);
283+
}
284+
285+
logParagraphs(); // Logs: Array of paragraphs or similar content
286+
287+
// Functions that take multiple arguments / the Rest parameter ...
288+
// Sometimes we don't know how many arguments we will receive, we can use the rest parameter in those cases.
289+
const total = (...numbers: number[]): number => {
290+
return numbers.reduce((total, num) => total + num, 0);
291+
};
292+
293+
log('Total: ', total(10, 256, 345, 465, 87, 432)); // Total: 1595
294+
295+
/* CLOSURES AND SCOPES */
296+
297+
// Scope: A scope refers to the visibility of identifiers in certain parts of a program.
298+
/* Closure: A closure allows a function to access and manipulate variables that are external to that function.
299+
Closures allow a function to access all the variables, as well as other functions, that are in scope when the function itself is defined.
300+
Hoisting is a mechanism that moves all variable and function declarations to the top of their scope.
301+
However, variable assignments still happen where they originally were. */
302+
303+
// This will work because doSomething is a Named Function and JavaScript hoists function declarations to the top of their containing scope.
304+
log(doSomething()); // I'm here coding, and I'm amazed at all we can learn by following this roadmap.
305+
306+
function doSomething(): void {
307+
console.log("I'm here coding, and I'm amazed at all we can learn by following this roadmap.");
308+
}
309+
310+
// This will throw an error because an anonymous function cannot be called before its declaration.
311+
// log(doAnotherthing());
312+
313+
let anotherthing = function () {
314+
console.log('never log this...');
315+
};
316+
317+
let friend = 'Asterix';
318+
319+
function showClosure(): void {
320+
log(friend); // Asterix in scope
321+
let anotherFriend = 'Obelix';
322+
function innerClosure(): void {
323+
let anotherOne = 'Idefix';
324+
log(anotherFriend); // Obelix in scope
325+
log(friend); // Asterix in scope
326+
log(anotherOne); // Idefix in scope
327+
}
328+
// log(anotherOne); // Throws an Error: anotherOne is not defined, is not in scope
329+
innerClosure();
330+
}
331+
332+
showClosure();
333+
// log(anotherFriend); // Throws an Error: anotherFriend is not defined, is not in scope
334+
335+
/* Closures let us do some interesting things, such as defining "private" variables that are visible only to a specific function or set of functions.
336+
A contrived (but popular) example: */
337+
const makeCounter = () => {
338+
let counter = 0;
339+
return {
340+
value: () => counter,
341+
increment: () => {
342+
counter++;
343+
},
344+
restart: () => {
345+
counter = 0;
346+
}
347+
};
348+
};
349+
350+
let counter1 = makeCounter();
351+
let counter2 = makeCounter();
352+
counter2.increment();
353+
counter2.increment();
354+
log(counter1.value()); // 0
355+
log(counter2.value()); // 2
356+
counter2.restart();
357+
log(counter2.value()); // 0
358+
359+
// Note: When makeCounter() is called, a snapshot of the context of that function is saved.
360+
// Note 2: Closures are also used to prevent global namespace pollution, often through the use of immediately-invoked function expressions.
361+
// Apply and Call
362+
function speak(this: { name: string }, ...sentences: string[]): void {
363+
let tell = '';
364+
sentences.forEach(word => tell += word + ' ');
365+
console.log(this.name + ": " + tell);
366+
}
367+
368+
let person = { name: "Niko" };
369+
speak.apply(person, ["I", "will", "go", "through", "this", "roadmap", "until", "the", "end"]); // Niko: I will go through this roadmap until the end
370+
speak.call(person, "But", "first", "I", "need", "some", "exercise"); // Niko: But first I need some exercise
371+
372+
/* Notice that apply allows you to pass an Array or the arguments object (array-like) as the list of arguments,
373+
whereas call requires you to pass each argument separately. */
374+
375+
/* As we see in the previous obj.advertisement() example:
376+
When using arrow functions, 'this' takes the value from the enclosing execution context's 'this' (that is,
377+
'this' in arrow functions has lexical scope rather than the usual dynamic scope).
378+
In global code (code that doesn't belong to any function), it would be the global object.
379+
And it keeps that way, even if you invoke the function declared with the arrow notation from any of the other methods here described. */
380+
381+
/* The bind method of every function allows you to create a new version of that function with the context strictly bound to a specific object.
382+
It is especially useful to force a function to be called as a method of an object. */
383+
384+
let person2 = { name: 'Anna' };
385+
386+
function sayHiLady(this: { name: string }): void {
387+
log(`Hi ${this.name}`);
388+
}
389+
390+
const hiAnna = sayHiLady.bind(person2);
391+
hiAnna(); // Hi Anna
392+
393+
/* This a possible output example for the previus logParagraphs() async function:
394+
[
395+
'Shank aliquip fugiat, cupim irure pig capicola kielbasa in mollit bresaola venison bacon aliqua. Alcatra aliqua jowl fatback pork chop in exercitation corned beef leberkas aliquip qui chicken consequat laboris. Swine shank porchetta tail quis in. Chuck dolore venison, picanha id swine cupim strip steak porchetta magna ball tip excepteur hamburger mollit ex. Picanha chislic irure strip steak sausage, in kevin ullamco. Magna pork belly tongue meatloaf elit tempor. Veniam meatball corned beef pork chop in.',
396+
'Sint ut deserunt pork loin enim doner sunt chuck qui occaecat aliqua meatloaf spare ribs exercitation. Shank esse cupidatat, boudin cupim eiusmod tenderloin occaecat do drumstick cow ut meatball. Aute non pig esse ea capicola landjaeger beef ad qui minim in boudin. Shank non dolore adipisicing. Ham hock drumstick sint landjaeger minim. Dolor in nisi chicken sunt.'
397+
] */

0 commit comments

Comments
 (0)