ES6 , Arrow Functions

Dokumentasi Exploring ES6 sub `Arrow Function`
Published di Javascript, 3 days ago

/**
* 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.


No image

Fadly Dzil Jalal

PHP, Yii2 Framework, Laravel, Java, Java Swing, Hibernate, Javascript, Angular, React, MySQL, MongoDB


Dapatkan USD 200 untuk develop aplikasimu di DigitalOcean DigitalOcean Referral Badge