/**
 * Bab 14 ARROW FUNCTIONS
 *
 * 14.1 Overview
 * There are two benefits to arrow functions.
 * 1. They are less verbose than traditional function expressions
 * 2. Their `this` is picked up from surroundings (lexical). Therefore, you don't need `bind()` or `that = this` anymore
 * 
    | Kasus                        | `this` milik siapa?                                     |
    | ---------------------------- | ------------------------------------------------------- |
    | Fungsi biasa (`function`)    | Bergantung pada siapa yang memanggil                    |
    | Arrow function (`=>`)        | Milik scope tempat arrow itu ditulis (lexical scope)    |
    | Dalam contoh `UiComponent()` | `this` milik konteks fungsi `UiComponent`, bukan button |
    | Di dalam `class`             | `this` biasanya merujuk ke instance class               |
    | Konsep                     | Penjelasan                                                          |
    | -------------------------- | ------------------------------------------------------------------- |
    | `lexical`                  | Ditentukan dari lokasi penulisan, bukan runtime                     |
    | `this` pada arrow function | Tidak punya sendiri, mewarisi dari lingkungan penulisan             |
    | Fungsi biasa vs arrow      | Fungsi biasa: `this` bergantung pada pemanggil; Arrow: `this` tetap |
    | Manfaat praktis            | Tidak perlu `bind(this)` atau `let that = this`                     |
 */
// 14.1 Overview Proven 1
// let arr = [1, 2, 3];
// let square = arr.map((x) => x * x);
// 14.1 Overview Proven 2
// function UiComponent() {
//   let button = document.getElementById("myButton");
//   button.addEventListener("click", () => {
//     console.log("click");
//     this.handleClick(); // lexical `this`
//   });
// }
/**
 * 
| Fitur        | Arrow Function Punya Sendiri? | Lexical Binding (diwarisi)? |
| ------------ | ----------------------------- | --------------------------- |
| `this`       | ‚ùå Tidak                       | ‚úÖ Ya                        |
| `arguments`  | ‚ùå Tidak                       | ‚úÖ Ya                        |
| `super`      | ‚ùå Tidak                       | ‚úÖ Ya                        |
| `new.target` | ‚ùå Tidak                       | ‚úÖ Ya                        |
* - Hal-hal ini menmbuat `arrow function` sangat berguna dalam konteks `class`, `callback`, dan `closure`
*   karena tidak perlu mengikat ulang `this
* - Tapi justru itu pula kenapa `arrow function` tidak cocok untuk `method` atau `constructor` -- karena
*   ia tidak punya `this` atatu `new.target` sendiri
*/
/**
 * 1. `this` -> Lexical in Arrow Function
 */
// class Person {
//   constructor(name) {
//     this.name = name;
//     setTimeout(() => {
//       console.log(this.name); // <- lexical this, which is Person, bukan milik setTimeOut
//     }, 2000);
//   }
// }
// let person = new Person("Dzil");
/**
 * 2. `arguments` -> Lexical in Arrow Function
 */
// function outer() {
//   const arrow = () => {
//     return arguments; // ini akan mengambil arguments dari `outer`, bukan dari `arrow`
//   };
//   return arrow("Wrong", "Scope");
// }
// console.log(outer("Dzil", "Fadly"));
/**
 * 3. `super` -> lexical in class Methods
 */
// class Parent {
//   greet() {
//     return "Hi from Parent";
//   }
// }
// class Child extends Parent {
//   greet() {
//     const arrow = () => super.greet(); // <- lexical super
//     return arrow();
//   }
// }
// class Child2 extends Parent {
//   greet() {
//     // solusi 1
//     const self = this;
//     function traditional() {
//       return Parent.prototype.greet.call(this); // bisa `this`, mengarah ke instance, atau `self` langsung panggil parent
//     }
//     return traditional.call(this);
//     // solusi 2
//     // const parentGreet = super.greet; // karena `super` masih bisa dipakai di scope `method class`
//     // function traditional() {
//     //   return parentGreet.call(this); // `this` disini harus disesuaikan
//     // }
//     // return traditional.call(this); // panggi dengan konteks yang benar
//   }
// }
// const c = new Child();
// console.log(c.greet());
// const c2 = new Child2();
// console.log(c2.greet());
/**
 * 4. new.target
 * new.target mengacu pada constructor yang sedang dipakai saat `new` dipanggil
 */
// function Factory() {
//   const arrow = () => {
//     console.log(new.target.name); // return `Factory`
//   };
//   arrow();
// }
// new Factory();
/**
 * 14.2 Traditional functions are bad non-method functions, due to `this`
 * In JavaScript, traditional functions can be used as:
 * 1. Non-method function
 * 2. Methods
 * 3. Constructors
 *
 * These roles class, due to roles 2and 3, function always have their `own` `this`.
 * But that prevents you from accessing the `this` e.g, surrounding method from inside a callback (role 1)
 */
/**
 * - In line C, we would like access that name that passed by an array argument
 * - But can not do that because the `this` of the function from line (B) shadows the `this` of the method from line (A)
 */
// function Prefixer(prefix) {
//   this.prefix = prefix;
// }
// Function (A)
// Prefixer.prototype.prefixArray = function (arr) {
//   "use strict";
//   // Function (B);
//   return arr.map(function (x) {
//     //console.log(this);
//     return this.prefix + x; // (C); mencoba mengakses `hi`, this sekarang `undefined`, lihat `role1`
//   });
// };
// Solution 1
// Prefixer.prototype.prefixArray = function (arr) {
//   "use strict";
//   var that = this; // `this` adalah instance Prefixer
//   return arr.map(function (x) {
//     console.log(`${that.prefix} ${x}`);
//     return that.prefix + x; // (C); mencoba mengakses `hi`
//   });
// };
// Solution 2, specifying a value for `this`
// Prefixer.prototype.prefixArray = function (arr) {
//   return arr.map(function (x) {
//     console.log(`${this.prefix} ${x}`); // (C) `${this}` akses dari second parameter `.map(callback, value)`
//   }, this);
// };
// Solution 3, `bind(this)`,
// convert a function whose `this` is determined by how it is called to a function whose `this` is always the same fixed value
// Prefixer.prototype.prefixArray = function (arr) {
//   "use strict";
//   return arr.map(
//     function (x) {
//       console.log(`${this.prefix} ${x}`);
//     }.bind(this)
//   );
// };
// Solution 4, ES6 Arrow function
// Prefixer.prototype.prefixArray = function (arr) {
//   return arr.map((x) => console.log(`${this.prefix} ${x}`));
// };
// Solution 5, ES5 turn to fully class based
// class Prefixer {
//   constructor(prefix) {
//     this.prefix = prefix;
//   }
//   prefixArray(arr) {
//     return arr.map((x) => console.log(`${this.prefix} ${x}`));
//   }
// }
// var prefixer = new Prefixer("hi");
// prefixer.prefixArray(["Joe", "Alex"]);
/**
 * 14.3 Arrow function syntax
 * `Fat arrow: =>`
 *
 *  ()   => { ... } // empty parameter
 *   x   => { ... } // one parameter, an identifier
 * (x,y) => { ... } // several parameters
 */
// let squares = [1, 2, 3].map(function (x) {
//   return x * x;
// });
//let squares = [1, 2, 3].map((x) => x * x); // implicit return
//console.log(squares);
/**
 * 14.4 Lexical variables
 */
/**
 * 14.4.1 Sources of variable values: static versus dynamic
 * The following are two ways in which a variable can receive its value
 */
// First, statically (lexically)
// let x = 123; // determined by the structure of program
// function foo(y) {
//   return x; // value receives statically
// }
// console.log(foo(12));
// // Second, dynamically
// function bar(arg) {
//   return arg; // value receives dynamically
// }
// console.log(bar(12));
/**
 * 14.4.2 Variables that are lexical in arrow functions
 * The source of `this` is an important distinguishing aspect of arrow functions
 * 
 * - Traditional functions have a `dynamic` `this`, its value is determined by how they are called
 * - Arrow functions have a `lexical` `this`, its value is determined by the sorrounding scope
 * 
 * The complete list of variables whose value are determined lexically is:
 * - arguments
 * - super
 * - this
 * - new.target
 * 
 * 
| Entity       | Traditional Function (`function`) | Arrow Function (`=>`)        |
| ------------ | --------------------------------- | ---------------------------- |
| `this`       | Dynamic (berubah-ubah)            | Lexical (mewarisi dari luar) |
| `arguments`  | Local untuk masing-masing fungsi  | Lexical dari scope luar      |
| `super`      | Tidak valid di function biasa     | Lexical dari class method    |
| `new.target` | Ada jika dipanggil dengan `new`   | Lexical dari fungsi luar     |
 */
/**
 * 14.5 Syntax pitfalls
 * 14.5.1 Arrow functions bind very loosely
 * Salah satu sifat sintaksis arrow function yang jarang dibahas tapi sangat penting:
 * yaitu bahwa arrow functions memiliki binding precedence (prioritas pengikatan operator) yang rendah.
 * Penggunaan tanda kurung `()` harap diperhatikan
 */
// console.log(typeof (() => {}));
// const f = (x) => typeof x;
/**
 * 14.5.2 Immediately-invoked arrow functions
 * Yang sudah dipelajari adalah `Immediately-invokef function expressions (IIFEs)` untuk meng-simulasi  `block-scoping` dan `value-returning blocks` di ES5
 *
 * `(function(){ // open IIFE
 *    // IIFED body inside
 * }()) // close IIFE`
 *
 * Jika ada premis:
 *
 * ```
 * const value = () => foo();
 * const value = () => (foo()); // true interpreted
 * const value = (() => foo)(); // false interpreted
 *
 * ```
 *
 */
// (() => {
//   console.log(123);
// })();
/**
 * 14.5.3 Omitting the parentheses around single parameters
 * => only possible if they consist of a single identifier
 */
// let variable = [1, 2, 3].map((x) => 2 * x);
// console.log(variable);
// let arr = [
//   [1, 2],
//   [3, 4],
// ];
// let variable2 = arr.map(([a, b]) => a + b); // [3, 7]
// let variable3 = arr.map((a, b) => a + b); // ['1,2', '3,41']
// // and you need parens if a single parameter has a default value (`undefined` triggers the default value!)
// let arr2 = [1, undefined, 3].map((x = "yes") => x);
// console.log(arr2);
/**
 * 14.5.4 You can`t use statements as expression bodies
 */
/**
 * 14.5.4.1 Expressions versus statements
 * Expressions produces (are evaluated to) values,eg `3+4` , `foo(7)`, `'abc'.length`
 * Statements do things, eg `while(true){ ... }`, `return 123`
 * 
| Fitur                               | Expression         | Statement                      |
| ----------------------------------- | ------------------ | ------------------------------ |
| Menghasilkan nilai?                 | ‚úÖ Ya               | ‚ùå Tidak                        |
| Bisa digunakan dalam ekspresi lain? | ‚úÖ Ya               | ‚ùå Tidak                        |
| Mengontrol alur?                    | ‚ùå Tidak            | ‚úÖ Ya                           |
| Bisa jadi bagian dari statement?    | ‚úÖ Ya               | ‚úÖ Ya                           |
| Contoh                              | `3+5`, `x = y * 2` | `if`, `for`, `return`, `break` |
 */
/**
 * 14.5.4.2 The bodies of arrow functions
 * If an expression is the body an arrow function, you don't need braces
 * If an statement  is the body an arrow function, you have to be put in braces
 */
/**
 * 14.5.5 Returning an object literal
 * If you wanth the expression body to be an `object literal` you have to put it in parentheses
 */
// let f1 = (x) => {bar: 123};     // block with the label bar and the expression statement 123
// let f2 = (x) => ({ bar: 123 }); // expression as `object literal`
// console.log(f1());
// console.log(f2());
/**
 * 14.6 Arrow functions versus normal functions
 * An arrow function is different from a normal function in only two ways
 *
 * 1. The following constructs are `lexical`: `arguments` , `super`, `this`, `new.target`
 * 2. It can not be used as a constructor. 
 *    There is no internal method `[[Construct]]` that allows a normal function to be invoked via `new`
 *    and no property `prototype`. Therefore , `new ( () => {}) ` must be throw an `Error`
 */
Dukung Saya supaya tetap menulis artikel-artikel yang baik, membayar sewa domain, dan server untuk blog ini. Caranya dengan donasi cendol via Trakteer.id.
                            
Komentar: 0
Login untuk meninggalkan komentar