Pure Function
Pure function เป็น function ที่มีคุณสมบัติสำคัญ 2 ประการ คือ
1. No Side Effect: ฟังก์ชันจะไม่เปลี่ยนแปลงค่าภายนอกหรือมีผลข้างเคียงใด ๆ กับโปรแกรม เช่น ไม่เปลี่ยนแปลงค่าของตัวแปร global, ไม่เขียนข้อมูลลงไฟล์ หรือส่งผลกระทบต่อฐานข้อมูล
2. Deterministic: ฟังก์ชันจะคืนค่า (return)
output เหมือนเดิมเสมอเมื่อได้รับ input ที่เหมือนเดิม
กล่าวอีกนัยหนึ่งคือ ฟังก์ชันจะต้องมีพฤติกรรมที่คาดเดาได้
Example: Pure function
function add(a: number, b: number): number {
return a + b;
}
ในตัวอย่างนี้ function add เป็น Pure function เนื่องจาก:
- ผลลัพธ์ของฟังก์ชันจะขึ้นอยู่กับ input a และ b เท่านั้น โดยไม่มีการเปลี่ยนแปลง state ภายนอก
- เมื่อใส่ค่าเดียวกัน เช่น add(2, 3) ทุกครั้งที่เรียกฟังก์ชันนี้จะได้ผลลัพธ์เป็น 5 เสมอ
Example: Impure function
let count = 0;
function increment(): number {
count += 1;
return count;
}
ในตัวอย่างนี้ increment เป็น Impure function เนื่องจาก:
- มีการเปลี่ยนแปลง state ภายนอก (ตัวแปร count)
- ผลลัพธ์ของฟังก์ชันไม่สามารถคาดเดาได้เสมอไป ถ้าเรียก increment() หลายครั้ง จะได้ผลลัพธ์ที่แตกต่างกัน เช่น ครั้งแรกได้ 1 ครั้งถัดไปอาจได้ 2, 3, เป็นต้น
function addRandomToNumber(num: number): number {
const randomValue = Math.random(); // ค่า random ไม่สามารถควบคุมได้
return num + randomValue;
}
ในตัวอย่างนี้ **addRandomToNumber** เป็น Impure function เนื่องจาก:
const result = addRandomToNumber(5); // ผลลัพธ์จะเปลี่ยนไปทุกครั้งที่เรียกใช้
ในกรณีนี้ addRandomToNumber เป็น Impure function เช่นกัน เนื่องจาก
- ฟังก์ชัน Math.random() ทำให้ค่าที่ส่งออกมาไม่สามารถคาดเดาได้ แม้ว่า input (num) จะเป็นค่าคงที่ เช่น 5 ผลลัพท์อาจจะออกมาเป็น 5.1 หรือ 5.82
Memoization
เป็นเทคนิคการเพิ่มประสิทธิภาพในโปรแกรมโดยการบันทึกผลลัพธ์ของ function ที่คำนวณแล้ว เพื่อหลีกเลี่ยงการคำนวณซ้ำ เมื่อ function ถูกเรียกซ้ำด้วย input เดิม ฟังก์ชันจะดึง output ที่บันทึกไว้มาใช้แทนการคำนวณใหม่
ตัวอย่างการใช้งาน Memoization
- ฟังก์ชัน Fibonacci แบบไม่ใช้ Memoization
function fibonacci(n: number): number {
if (n <= 1) {
return n;
}
return fibonacci(n - 1) + fibonacci(n - 2);
}
ในกรณีนี้ การคำนวณ Fibonacci แบบ recursive ทำให้เกิดการเรียกฟังก์ชันซ้ำ ๆ กันมากมาย ส่งผลให้เกิดการคำนวณซ้ำซ้อน และทำให้โปรแกรมทำงานช้าลง
- ฟังก์ชัน Fibonacci แบบใช้ Memoization
function memoizedFibonacci(): (n: number) => number {
const cache: { [key: number]: number } = {};
return function fib(n: number): number {
if (n in cache) {
return cache[n]; // คืนค่าจาก cache ถ้ามีอยู่
}
if (n <= 1) {
return n;
}
const result = fib(n - 1) + fib(n - 2);
cache[n] = result; // บันทึกผลลัพธ์ใน cache
return result;
};
}
First-Class Functions
ทำให้ภาษาสามารถจัดการกับ function ได้เหมือนข้อมูลทั่วไป
1. การเก็บฟังก์ชันในตัวแปร
// เก็บฟังก์ชันในตัวแปร
const greet = function(name: string): string {
return `Hello, ${name}!`;
};
2. การส่งผ่านฟังก์ชันเป็นพารามิเตอร์
function greet(name: string): string {
return `Hello, ${name}!`;
}
function printMessage(func: (name: string) => string, name: string): void {
console.log(func(name));
}
3. การคืนค่าฟังก์ชันจากฟังก์ชัน
function createGreeting(greeting: string) {
return function(name: string): string {
return `${greeting}, ${name}!`;
};
}
4. การใช้ฟังก์ชันภายในโครงสร้างข้อมูล
const operations = {
add: (a: number, b: number) => a + b,
subtract: (a: number, b: number) => a - b,
multiply: (a: number, b: number) => a * b,
divide: (a: number, b: number) => a / b
};
Immutable
คือ ข้อมูลหรือค่าที่ไม่สามารถเปลี่ยนแปลงได้หลังจากที่ถูกสร้างขึ้นมาแล้ว ในการเขียนโค้ดแบบ Immutable ทุกครั้งที่ต้องการเปลี่ยนแปลงข้อมูล จะต้องสร้างข้อมูลใหม่ขึ้นมาแทนการแก้ไขข้อมูลเดิม
ประโยขน์
1. Prevent Side Effects: เนื่องจากข้อมูลไม่ถูกเปลี่ยนแปลงโดยไม่ตั้งใจ โปรแกรมสามารถทำงานได้อย่างน่าเชื่อถือมากขึ้น
2. Traceable: การติดตามการเปลี่ยนแปลงของข้อมูลทำได้ง่ายขึ้น เพราะข้อมูลไม่ถูกแก้ไข
3. Race Conditions: การใช้ข้อมูลแบบ Immutable ช่วยป้องกันปัญหาที่เกิดจากการแก้ไขข้อมูลพร้อมกัน
Object
Example: Mutable
const person = { name: "Alice", age: 25 };
person.name = "Bob"
Example: Immutable
const person = { name: "Alice", age: 25 };
// สร้างออบเจ็กต์ใหม่ โดยไม่เปลี่ยนแปลงข้อมูลเดิม
const updatedPerson = { ...person, age: 26 };
const updatedPerson2 = Object.assign(person, { age: 28 })
Primitive data type
- number
- bigint
- string
- boolean
- null
- undefined
- symbol
ทั้งหมดเป็น Immutable เมื่อเราทำการสร้างค่าขึ้นใหม่จากค่าที่มีอยู่แล้ว การเปลี่ยนแปลงค่าในตัวแปรจะส่งผลให้มีการสร้างค่าใหม่แทนที่จะเปลี่ยนแปลงค่าดั้งเดิม
Array
Example: Mutable
const arr = [1, 2, 3];
arr.push(4); // เปลี่ยนแปลงข้อมูลใน arr
console.log(arr); // [1, 2, 3, 4]
Example: Immutable
const arr = [1, 2, 3];
// สร้างอาร์เรย์ใหม่แทนการแก้ไขของเดิม
const newArr = [...arr, 4];
Solution
Operation | avoid(mutate) | prefer (new array) |
---|---|---|
adding | push, unshift | concat, [...arr] |
removing | pop, shift, splice | filter, slice |
replacing | splice, arr[i] = ... | map |
sorting | reverse, sort | [...arr].sort() |
Thinking in React
*1. แบ่ง UI ออกเป็น Component
*
- FilterableProductTable: (สีเทา): container ของหน้านี้
- SearchBar (สีน้ำเงิน): รับข้อมูลจาก user เพื่อกรองข้อมูล
- ProductTable (สีม่วง): แสดง list ของข้อมูลสินค้า
- ProductCategoryRow (สีเขียว): แสดงข้อมูลกลุ่มของสินค้า
- ProductRow (สีเหลือง): แสดงข้อมูลของสินค้า
2. Create Static UI
Props กับ State
1. Props คือ ข้อมูลที่ parent component ส่งให้กับ child component เพื่อปรับแต่งลักษณะการแสดงผลได้ เช่น form สามารถส่ง props สีไปยังปุ่ม button ได้
2. State คือ เปรียบเสมือนหน่วยความจำของคอมโพเนนต์ โดยช่วยให้คอมโพเนนต์ติดตามข้อมูลบางอย่างและเปลี่ยนแปลงได้ตามการโต้ตอบของผู้ใช้ เช่น ปุ่ม Button อาจติดตาม state ที่บ่งบอกสถานะการชี้เมาส์ (isHovered) State is reserved only for interactivity
Props และ State นั้นแตกต่างกัน แต่ทำงานร่วมกันได้ดี parent component จะเก็บข้อมูลบางอย่างใน state (เพื่อให้สามารถเปลี่ยนแปลงได้) แล้วส่งข้อมูลเหล่านั้นไปยังคอมโพเนนต์ลูกในรูปแบบของ props
Top comments (0)