# สัปดาห์ที่ 5: Functions (ฟังก์ชัน)

## 📚 สารบัญ

1. [Functions คืออะไร](#functions-intro)
2. [ประเภทของ Functions](#function-types)
3. [Parameters และ Arguments](#parameters)
4. [Return Value](#return-value)
5. [Scope และ Closure](#scope-closure)
6. [Higher-Order Functions](#higher-order)
7. [Callback Functions](#callbacks)
8. [Best Practices](#best-practices)
9. [ตัวอย่างจริง](#practical-examples)
10. [แบบฝึกหัด](#exercises)

---

## Functions คืออะไร {#functions-intro}

### คำนิยาม

ฟังก์ชันคือ code block ที่ทำงานเฉพาะและสามารถนำมาใช้ซ้ำได้หลายครั้ง

### ทำไมต้องใช้ Functions?

```javascript
// ❌ ไม่ดี - ซ้ำซ้อน
console.log("สวัสดี สมชาย");
console.log("สวัสดี จิตรา");
console.log("สวัสดี นัทสยา");

// ✅ ดี - ใช้ function
function greet(name) {
  console.log("สวัสดี " + name);
}

greet("สมชาย");
greet("จิตรา");
greet("นัทสยา");
```

### ประโยชน์ของ Functions

- **Reusability** - ใช้ซ้ำได้
- **Readability** - โค้ดอ่านง่าย
- **Maintainability** - ดูแลรักษาง่าย
- **Testing** - ทดสอบง่าย
- **Organization** - จัดระเบียบ code

---

## ประเภทของ Functions {#function-types}

### 1. Function Declaration (ประกาศฟังก์ชัน)

#### คำอธิบาย

Function Declaration คือวิธีการประกาศฟังก์ชันที่ใช้คำว่า `function` ตามด้วยชื่อ ลักษณะนี้ถือเป็น Statement ของ JavaScript และ JavaScript engine จะ hoisting ทำให้สามารถเรียกใช้ได้ก่อนการประกาศ

#### ข้อดี

- ✅ สามารถเรียกใช้ก่อนประกาศ (Hoisting)
- ✅ อ่านง่าย เหมาะสำหรับฟังก์ชันหลัก
- ✅ เก็บใน memory ทั้งหมดก่อนโค้ดทำงาน

#### ข้อเสีย

- ❌ อาจเบลอ scope หากใช้มากเกินไป
- ❌ ไม่สามารถกำหนด conditional declaration ได้

```javascript
// ประกาศ function
function greet(name) {
  console.log("สวัสดี " + name);
}

// เรียกใช้
greet("สมชาย"); // สวัสดี สมชาย

// ✅ สามารถเรียกใช้ก่อนประกาศได้ (Hoisting)
sayHello(); // สวัสดี!

function sayHello() {
  console.log("สวัสดี!");
}

// นี่เกิดจาก Hoisting - ก่อนที่โค้ดทำงาน JS จะ "ยกขึ้น" function declaration ไปด้านบน
// ลำดับจริงที่เกิดขึ้นจะเป็น:
// function sayHello() { ... }
// sayHello(); // เรียกใช้
```

### 2. Function Expression (นิพจน์ฟังก์ชัน)

#### คำอธิบาย

Function Expression คือการกำหนดฟังก์ชันให้กับตัวแปร เป็นค่า (value) ของตัวแปร ทำให้สามารถส่งต่อและเก็บเป็นค่าได้ เหมือนตัวแปรธรรมดา

#### ข้อดี

- ✅ มีความยืดหยุ่นสูง สามารถส่งเป็น argument ได้
- ✅ ไม่เกิด hoisting ทำให้ดูเจตนาชัด
- ✅ สามารถสร้าง closure ได้ง่าย
- ✅ สามารถตั้งชื่อ (Named) หรือไม่ตั้งชื่อ (Anonymous)

#### ข้อเสีย

- ❌ ไม่สามารถเรียกใช้ก่อนประกาศได้ (ReferenceError)
- ❌ ต้องประกาศก่อนใช้เสมอ

```javascript
// Anonymous function expression
const greet = function (name) {
  console.log("สวัสดี " + name);
};

greet("สมชาย"); // สวัสดี สมชาย

// Named function expression (มีชื่อด้วย)
const factorial = function fact(n) {
  if (n <= 1) return 1;
  return n * fact(n - 1); // สามารถเรียกตัวเองได้ด้วยชื่อ fact
};

console.log(factorial(5)); // 120
console.log(typeof fact); // undefined (fact ไม่เข้าถึงได้จากนอก)

// ❌ ไม่สามารถเรียกใช้ก่อนประกาศได้
// greet("สมชาย"); // ReferenceError: Cannot access 'greet' before initialization

// สาเหตุ: Temporal Dead Zone - ตัวแปรถูกสร้างแล้วแต่ยังไม่ได้ assign ค่า
```

### 3. Arrow Function (ฟังก์ชันลูกศร)

#### คำอธิบาย

Arrow Function เป็นวิธีการเขียนฟังก์ชันแบบ concise ที่ใช้ลูกศร `=>` แนะนำใน ES6 (2015) ทำให้โค้ดสั้นและอ่านง่าย มีคุณสมบัติพิเศษเรื่อง `this` binding

#### ข้อดี

- ✅ Syntax สั้น โปรแกรมเมอร์สามารถเขียนน้อยกว่า
- ✅ Implicit return ทำให้โค้ดสั้นลง
- ✅ `this` bind ไปยัง outer context ทำให้หลีกเลี่ยงปัญหา `this`
- ✅ Perfect สำหรับ array methods (map, filter, reduce)

#### ข้อเสีย

- ❌ ไม่มี `arguments` object (ใช้ rest parameters แทน)
- ❌ ไม่สามารถใช้เป็น constructor ได้
- ❌ ไม่เหมาะสำหรับ methods ของ object เมื่อต้องการ `this` binding

```javascript
// Syntax แบบปกติ
const greet = (name) => {
  console.log("สวัสดี " + name);
};

greet("สมชาย"); // สวัสดี สมชาย

// Syntax สั้น (1 parameter ไม่ต้องวงเล็บ)
const square = (x) => {
  return x * x;
};

console.log(square(5)); // 25

// Syntax สั้นสุด (implicit return - ไม่ต้องมี return keyword)
const add = (a, b) => a + b;

console.log(add(3, 5)); // 8

// Multiple parameters
const multiply = (a, b) => a * b;
console.log(multiply(4, 5)); // 20

// No parameters (ต้องมีวงเล็บเปล่า)
const getRandomNumber = () => Math.random();
console.log(getRandomNumber()); // 0.123...

// ⚠️ ระวัง: Implicit return กับ object
// ❌ ผิด - JavaScript คิดว่า {} คือ function body
const person = () => {
  name: "John";
};
console.log(person()); // undefined

// ✅ ถูก - ใช้วงเล็บ
const person2 = () => ({ name: "John" });
console.log(person2()); // { name: "John" }

// ตัวอย่าง this binding ความแตกต่าง
const obj = {
  name: "Object",
  // ❌ Arrow function ไม่ bind this ไปยัง obj
  arrowGreet: () => {
    console.log(this); // window or global object
  },
  // ✅ Regular function bind this ไปยัง obj
  regularGreet: function () {
    console.log(this); // { name: "Object", ... }
  },
};

obj.arrowGreet(); // window
obj.regularGreet(); // obj
```

### 4. Function Constructor (ไม่แนะนำ)

#### คำอธิบาย

Function Constructor เป็นวิธีการสร้างฟังก์ชันโดยใช้ `new Function()` นี่เป็นวิธีที่พบได้ไม่บ่อย และไม่แนะนำให้ใช้เพราะมีปัญหาด้าน performance และ security

#### ข้อเสีย

- ❌ Performance ต่ำ - code string ต้องถูก parse ทุกครั้งที่เรียกใช้
- ❌ Security risk - หากอยู่ใน eval-like สภาพแวดล้อม
- ❌ ยากต่อการ debug
- ❌ ไม่มี closure support
- ❌ อ่านยาก

```javascript
// ❌ ไม่ดี - หลีกเลี่ยง
const add = new Function("a", "b", "return a + b");
console.log(add(3, 5)); // 8

// ✅ ดี - ใช้ function declaration หรือ arrow function แทน
const addGood = (a, b) => a + b;
console.log(addGood(3, 5)); // 8
```

### เปรียบเทียบประเภท Functions

| ประเภท      | Hoisting | this       | Arrow  | สถานที่ใช้                     |
| ----------- | -------- | ---------- | ------ | ------------------------------ |
| Declaration | ✅ Yes   | dynamic    | ❌ No  | Main functions                 |
| Expression  | ❌ No    | dynamic    | ✅ Yes | Callbacks, stored functions    |
| Arrow       | ❌ No    | ❌ Inherit | ✅ Yes | Array methods, short functions |
| Constructor | ❌ No    | dynamic    | ❌ No  | ❌ Avoid                       |

### ตัวอย่างการเลือกใช้

```javascript
// 1. Main function ใช้ Declaration
function processData(data) {
  // logic
}

// 2. Callback function ใช้ Arrow
const numbers = [1, 2, 3, 4, 5];
const doubled = numbers.map((n) => n * 2);

// 3. Complex callback ใช้ Expression
const users = [
  { id: 1, name: "John" },
  { id: 2, name: "Jane" },
];

const filtered = users.filter(function (user) {
  return user.name.length > 4;
});

// 4. Object method ใช้ function expression
const calculator = {
  value: 0,
  add: function (x) {
    this.value += x;
    return this;
  },
};

calculator.add(5).add(3); // this bind ไปยัง calculator
```

---

## Parameters และ Arguments {#parameters}

### คำอธิบาย

Parameters และ Arguments มักจะใช้แทนกัน แต่มีความหมายต่างกัน:

- **Parameters** คือตัวแปรที่ประกาศในการนิยาม function
- **Arguments** คือค่าจริงที่ส่งเข้าไปเมื่อเรียกใช้ function

การเข้าใจความแตกต่างนี้สำคัญเพราะจะช่วยให้คุณสามารถใช้งาน functions ได้อย่างถูกต้องและหลีกเลี่ยงปัญหา

### ความแตกต่าง

```javascript
// Parameters - ตัวแปรในการประกาศ function
function greet(name, age) {
  //   ↑     ↑
  // Parameters
}

// Arguments - ค่าที่ส่งเข้า
greet("สมชาย", 25);
//     ↑         ↑
//   Arguments
```

### ประเภทต่างๆ

#### 1. Multiple Parameters

```javascript
function add(a, b) {
  return a + b;
}

console.log(add(3, 5)); // 8
console.log(add(10, 20)); // 30
```

#### 2. Default Parameters

```javascript
function greet(name = "Friend") {
  console.log("สวัสดี " + name);
}

greet("สมชาย"); // สวัสดี สมชาย
greet(); // สวัสดี Friend

// Multiple defaults
function createUser(name = "Unknown", age = 0, role = "user") {
  console.log(name, age, role);
}

createUser("สมชาย", 25); // สมชาย 25 user
createUser("สมชาย", 25, "admin"); // สมชาย 25 admin
createUser(); // Unknown 0 user
```

#### 3. Rest Parameters (...)

```javascript
// เรียบเรียง parameter ที่เหลือเป็น array
function sum(...numbers) {
  console.log(numbers); // [1, 2, 3, 4, 5]
  return numbers.reduce((a, b) => a + b, 0);
}

console.log(sum(1, 2, 3, 4, 5)); // 15
console.log(sum(10, 20)); // 30

// Mix regular parameters and rest
function greetPeople(greeting, ...names) {
  names.forEach((name) => {
    console.log(greeting + " " + name);
  });
}

greetPeople("สวัสดี", "สมชาย", "จิตรา", "นัทสยา");
// สวัสดี สมชาย
// สวัสดี จิตรา
// สวัสดี นัทสยา
```

#### 4. Destructuring Parameters

```javascript
// Object destructuring
function printUser({ name, age, email }) {
  console.log(name); // 'สมชาย'
  console.log(age); // 25
  console.log(email); // 'somchai@example.com'
}

const user = {
  name: "สมชาย",
  age: 25,
  email: "somchai@example.com",
};

printUser(user);

// Array destructuring
function printCoordinates([x, y]) {
  console.log("X:", x);
  console.log("Y:", y);
}

const point = [10, 20];
printCoordinates(point); // X: 10, Y: 20
```

---

## Return Value {#return-value}

### คำอธิบาย

Return value คือค่าที่ function ส่งกลับมาให้เราใช้งาน Function สามารถ return ได้:

- ค่าเดียว (number, string, boolean, object, array ฯลฯ)
- ไม่ return (undefined)
- Multiple values ผ่านการส่งกลับ object หรือ array

การใช้ return ที่ดีทำให้ code readable และ reusable มากขึ้น

### ค่าที่ส่งกลับ

```javascript
// Function ที่ return ค่า
function add(a, b) {
  return a + b;
}

const result = add(3, 5);
console.log(result); // 8

// Function ที่ไม่ return (default return undefined)
function greet(name) {
  console.log("สวัสดี " + name);
  // ไม่มี return
}

const greeting = greet("สมชาย");
console.log(greeting); // undefined
```

### Multiple Returns

```javascript
// Return object
function getCoordinates() {
  return {
    x: 10,
    y: 20,
  };
}

const coords = getCoordinates();
console.log(coords.x); // 10

// Return array
function getMinAndMax(numbers) {
  return [Math.min(...numbers), Math.max(...numbers)];
}

const [min, max] = getMinAndMax([5, 2, 9, 1, 7]);
console.log(min, max); // 1 9

// Early return
function validateAge(age) {
  if (age < 0) {
    return "Age cannot be negative";
  }
  if (age < 18) {
    return "You are a minor";
  }
  return "You are an adult";
}

console.log(validateAge(25)); // You are an adult
console.log(validateAge(15)); // You are a minor
console.log(validateAge(-5)); // Age cannot be negative
```

---

## Scope และ Closure {#scope-closure}

### คำอธิบาย Scope

Scope คือพื้นที่หรือบริบทที่ตัวแปรสามารถเข้าถึงได้ JavaScript มี scope หลัก 3 ประเภท:

- **Global Scope** - เข้าถึงได้ทุกที่ใน code
- **Function Scope** - เข้าถึงได้เฉพาะภายใน function
- **Block Scope** - เข้าถึงได้เฉพาะภายใน block (if, for, while ฯลฯ) เมื่อใช้ let, const

การเข้าใจ scope ช่วยหลีกเลี่ยงปัญหา naming conflict และ memory leak

### คำอธิบาย Closure

Closure คือ function ที่สามารถเข้าถึงตัวแปรจาก outer scope ได้ แม้ว่า outer function จะ return ไปแล้ว Closure มีประโยชน์มากในการ:

- สร้าง private variables
- Data encapsulation
- Factory functions
- Callback functions

### Global Scope

```javascript
// Global scope
const globalVar = "Global";

function testGlobal() {
  console.log(globalVar); // 'Global' - เข้าถึงได้
}

testGlobal();
console.log(globalVar); // 'Global'
```

### Local Scope (Function Scope)

```javascript
function testLocal() {
  const localVar = "Local";
  console.log(localVar); // 'Local' - เข้าถึงได้
}

testLocal();
console.log(localVar); // ❌ Error - localVar ไม่มี global
```

### Block Scope (let, const)

```javascript
function testBlockScope() {
  if (true) {
    const blockVar = "Block";
    console.log(blockVar); // 'Block'
  }
  console.log(blockVar); // ❌ Error - blockVar ไม่มี
}

testBlockScope();

// var ไม่ได้ block scope
function testVarScope() {
  if (true) {
    var varVar = "Var";
  }
  console.log(varVar); // 'Var' - var ไม่มี block scope ❌
}

testVarScope();
```

### Scope Chain (Lexical Scope)

```javascript
const global = "Global";

function outer() {
  const outerVar = "Outer";

  function inner() {
    const innerVar = "Inner";
    console.log(innerVar); // 'Inner' - local
    console.log(outerVar); // 'Outer' - outer function
    console.log(global); // 'Global' - global
  }

  inner();
  console.log(innerVar); // ❌ Error - innerVar ไม่มี
}

outer();
```

### Closure

Closure คือ function ที่เข้าถึงตัวแปรจาก outer scope ได้

```javascript
// ตัวอย่างที่ 1: Simple Closure
function makeAdder(x) {
  return function (y) {
    return x + y;
  };
}

const add5 = makeAdder(5);
const add10 = makeAdder(10);

console.log(add5(3)); // 8 (5 + 3)
console.log(add10(3)); // 13 (10 + 3)

// ตัวอย่างที่ 2: Counter with Closure
function makeCounter() {
  let count = 0; // Private variable

  return {
    increment: function () {
      count++;
      return count;
    },
    decrement: function () {
      count--;
      return count;
    },
    getCount: function () {
      return count;
    },
  };
}

const counter = makeCounter();
console.log(counter.increment()); // 1
console.log(counter.increment()); // 2
console.log(counter.decrement()); // 1
console.log(counter.getCount()); // 1

// count ไม่สามารถเข้าถึงโดยตรง
console.log(counter.count); // undefined

// ตัวอย่างที่ 3: Closure in Loop
const functions = [];

for (var i = 0; i < 3; i++) {
  functions.push(function () {
    return i; // ❌ ผิด - i จะเป็น 3 เสมอ
  });
}

console.log(functions[0]()); // 3 (ไม่ใช่ 0)
console.log(functions[1]()); // 3 (ไม่ใช่ 1)

// ✅ แก้ด้วย IIFE
const correctFunctions = [];

for (var i = 0; i < 3; i++) {
  correctFunctions.push(
    (function (j) {
      return function () {
        return j;
      };
    })(i)
  );
}

console.log(correctFunctions[0]()); // 0 ✅
console.log(correctFunctions[1]()); // 1 ✅

// ✅ หรือใช้ let ง่ายกว่า
const bestFunctions = [];

for (let i = 0; i < 3; i++) {
  bestFunctions.push(function () {
    return i;
  });
}

console.log(bestFunctions[0]()); // 0 ✅
console.log(bestFunctions[1]()); // 1 ✅
```

---

## Higher-Order Functions {#higher-order}

### คำอธิบาย

Higher-Order Function (HOF) คือ function ที่ทำให้ functions กลายเป็น "first-class citizens" ในภาษา นั่นหมายความว่า functions สามารถ:

- ส่งเป็น argument ไปยัง function อื่นได้
- Return function ได้
- เก็บไว้ในตัวแปร array หรือ object ได้

ประโยชน์ของ HOF:

- ทำให้ code มี flexibility สูง
- ลดการซ้ำซ้อน
- ทำให้เข้าใจ functional programming paradigm
- Array methods (map, filter, reduce) เป็นตัวอย่างของ HOF ทั่วไป

### คืออะไร?

Higher-Order Function คือ function ที่:

- รับ function เป็น parameter หรือ
- Return function

```javascript
// Function ที่รับ function เป็น parameter
function executeFunction(fn) {
  return fn();
}

const sayHello = () => "สวัสดี!";
console.log(executeFunction(sayHello)); // สวัสดี!

// Function ที่ return function
function makeMultiplier(multiplier) {
  return function (number) {
    return number * multiplier;
  };
}

const double = makeMultiplier(2);
const triple = makeMultiplier(3);

console.log(double(5)); // 10
console.log(triple(5)); // 15
```

### ตัวอย่างจริง

#### 1. Array Methods (map, filter, reduce)

```javascript
const numbers = [1, 2, 3, 4, 5];

// map - แปลง array
const doubled = numbers.map(function (num) {
  return num * 2;
});
console.log(doubled); // [2, 4, 6, 8, 10]

// filter - กรอง array
const evens = numbers.filter(function (num) {
  return num % 2 === 0;
});
console.log(evens); // [2, 4]

// reduce - รวม array
const sum = numbers.reduce(function (acc, num) {
  return acc + num;
}, 0);
console.log(sum); // 15
```

#### 2. Function Composition

```javascript
const addTwo = (x) => x + 2;
const multiplyByThree = (x) => x * 3;
const subtractOne = (x) => x - 1;

// Compose functions (ขวาไปซ้าย)
function compose(...functions) {
  return function (value) {
    return functions.reduceRight((result, fn) => fn(result), value);
  };
}

const compute = compose(subtractOne, multiplyByThree, addTwo);
console.log(compute(5)); // ((5 + 2) * 3) - 1 = 20

// Pipe functions (ซ้ายไปขวา)
function pipe(...functions) {
  return function (value) {
    return functions.reduce((result, fn) => fn(result), value);
  };
}

const compute2 = pipe(addTwo, multiplyByThree, subtractOne);
console.log(compute2(5)); // ((5 + 2) * 3) - 1 = 20
```

#### 3. Memoization

```javascript
// Fibonacci โดยไม่ memoize (ช้า)
function fibonacci(n) {
  if (n <= 1) return n;
  return fibonacci(n - 1) + fibonacci(n - 2);
}

// Fibonacci ด้วย memoization (เร็ว)
function memoize(fn) {
  const cache = {};

  return function (n) {
    if (n in cache) {
      return cache[n];
    }
    const result = fn(n);
    cache[n] = result;
    return result;
  };
}

const fibMemo = memoize(function (n) {
  if (n <= 1) return n;
  return fibMemo(n - 1) + fibMemo(n - 2);
});

console.log(fibMemo(10)); // 55 (เร็วมาก)
```

---

## Callback Functions {#callbacks}

### คำอธิบาย

Callback Function คือ pattern ทั่วไปในการให้ function รอการตอบสนองหรือการทำงานเสร็จ Callback ใช้ได้ในหลาย scenario:

- **Asynchronous operations** - เมื่อต้องรอการทำงาน (setTimeout, fetch ฯลฯ)
- **Event handling** - เมื่อ event เกิดขึ้น ให้เรียกใช้ callback
- **Array methods** - map, filter, reduce เป็น callback patterns
- **Function chaining** - ส่งผลลัพธ์ไปยัง callback ถัดไป

### ข้อดี

- ✅ ทำให้ code asynchronous ได้ง่าย
- ✅ ยืดหยุ่นสำหรับ event-driven programming

### ข้อเสีย

- ❌ Callback Hell - nested callbacks ทำให้อ่านยาก
- ❌ Error handling ซับซ้อน

### คืออะไร?

Callback คือ function ที่ส่งเข้าไปใน function อื่น เพื่อให้เรียกใช้ภายหลัง

```javascript
// ตัวอย่างง่าย
function greet(name, callback) {
  console.log("สวัสดี " + name);
  callback();
}

function sayGoodbye() {
  console.log("ลาก่อน");
}

greet("สมชาย", sayGoodbye);
// สวัสดี สมชาย
// ลาก่อน
```

### Callback with Parameters

```javascript
function processNumber(num, callback) {
  const result = num * 2;
  callback(result);
}

processNumber(5, function (result) {
  console.log("ผลลัพธ์:", result); // ผลลัพธ์: 10
});

// Arrow function
processNumber(10, (result) => {
  console.log("ผลลัพธ์:", result); // ผลลัพธ์: 20
});
```

### Callback Hell (Pyramid of Doom)

```javascript
// ❌ ไม่ดี - nested callbacks
function loadUser(userId, callback) {
  setTimeout(() => {
    callback({ id: userId, name: "สมชาย" });
  }, 1000);
}

function loadPosts(userId, callback) {
  setTimeout(() => {
    callback([
      { id: 1, title: "Post 1" },
      { id: 2, title: "Post 2" },
    ]);
  }, 1000);
}

function loadComments(postId, callback) {
  setTimeout(() => {
    callback([
      { id: 1, text: "Comment 1" },
      { id: 2, text: "Comment 2" },
    ]);
  }, 1000);
}

// Callback hell
loadUser(1, (user) => {
  console.log("User:", user);

  loadPosts(user.id, (posts) => {
    console.log("Posts:", posts);

    loadComments(posts[0].id, (comments) => {
      console.log("Comments:", comments);
    });
  });
});
```

### ✅ แนวทางแก้: Promises และ Async/Await

```javascript
// ✅ ดี - Promises
loadUser(1)
  .then((user) => {
    console.log("User:", user);
    return loadPosts(user.id);
  })
  .then((posts) => {
    console.log("Posts:", posts);
    return loadComments(posts[0].id);
  })
  .then((comments) => {
    console.log("Comments:", comments);
  });

// ✅ ดีที่สุด - Async/Await
async function getAllData() {
  const user = await loadUser(1);
  console.log("User:", user);

  const posts = await loadPosts(user.id);
  console.log("Posts:", posts);

  const comments = await loadComments(posts[0].id);
  console.log("Comments:", comments);
}

getAllData();
```

---

## Best Practices {#best-practices}

### คำอธิบาย

Best Practices สำหรับ functions ช่วยให้:

- Code readable และ maintainable
- หลีกเลี่ยง bugs
- ทำให้ collaboration กับ developers อื่นง่ายขึ้น
- Code review เป็นไปอย่างสมูท

การปฏิบัติตามหลัก best practices ช่วยให้เป็น professional developer ได้

### 1. ใช้ Meaningful Names

```javascript
// ❌ ไม่ดี
function x(a, b) {
  return a + b;
}

// ✅ ดี
function calculateTotal(price, tax) {
  return price + tax;
}
```

### 2. Single Responsibility

```javascript
// ❌ ไม่ดี - ทำหลายอย่าง
function processUser(user) {
  // Validate
  if (!user.name) {
    console.log("Invalid user");
    return;
  }

  // Save to database
  database.save(user);

  // Send email
  email.send(user.email, "Welcome!");

  // Log
  console.log("User saved");
}

// ✅ ดี - แต่ละ function มี 1 responsibility
function validateUser(user) {
  return user.name && user.email;
}

function saveUser(user) {
  database.save(user);
}

function sendWelcomeEmail(user) {
  email.send(user.email, "Welcome!");
}

function processUser(user) {
  if (!validateUser(user)) return;
  saveUser(user);
  sendWelcomeEmail(user);
}
```

### 3. Keep Functions Small

```javascript
// ❌ ไม่ดี - function ยาว
function calculateOrderTotal(items) {
  let subtotal = 0;

  for (let i = 0; i < items.length; i++) {
    subtotal += items[i].price * items[i].quantity;
  }

  const tax = subtotal * 0.1;
  const discount = items.length > 10 ? subtotal * 0.05 : 0;
  const shipping = subtotal > 100 ? 0 : 10;

  return subtotal + tax - discount + shipping;
}

// ✅ ดี - แบ่งเป็น functions เล็กๆ
function calculateSubtotal(items) {
  return items.reduce((sum, item) => sum + item.price * item.quantity, 0);
}

function calculateTax(subtotal) {
  return subtotal * 0.1;
}

function calculateDiscount(items, subtotal) {
  return items.length > 10 ? subtotal * 0.05 : 0;
}

function calculateShipping(subtotal) {
  return subtotal > 100 ? 0 : 10;
}

function calculateOrderTotal(items) {
  const subtotal = calculateSubtotal(items);
  const tax = calculateTax(subtotal);
  const discount = calculateDiscount(items, subtotal);
  const shipping = calculateShipping(subtotal);

  return subtotal + tax - discount + shipping;
}
```

### 4. ใช้ Default Parameters

```javascript
// ❌ ไม่ดี
function greet(name) {
  if (!name) {
    name = "Friend";
  }
  console.log("สวัสดี " + name);
}

// ✅ ดี
function greet(name = "Friend") {
  console.log("สวัสดี " + name);
}
```

### 5. ใช้ Const สำหรับ Functions

```javascript
// ❌ ไม่ดี
let add = function (a, b) {
  return a + b;
};

// ✅ ดี
const add = (a, b) => a + b;
```

### 6. Avoid Global Variables

```javascript
// ❌ ไม่ดี
let globalCount = 0;

function increment() {
  globalCount++;
  return globalCount;
}

// ✅ ดี
function makeCounter() {
  let count = 0;

  return function () {
    count++;
    return count;
  };
}

const increment = makeCounter();
```

---

## ตัวอย่างจริง {#practical-examples}

### คำอธิบาย

ตัวอย่างจริงแสดงให้เห็นว่าสิ่งที่เราเรียนรู้นั้นสามารถนำไปใช้ในโลกจริงได้อย่างไร ตัวอย่างเหล่านี้ครอบคลุม:

- Object utilities - ใช้ object เก็บ related functions
- Data validation - ทำให้ code ปลอดภัยและเชื่อถือได้
- Data transformation - แปลงข้อมูลจากรูปแบบหนึ่งไปอีกรูปแบบหนึ่ง
- Function composition - รวม functions เล็กๆ เป็นการทำงาน complex

การศึกษาตัวอย่างจริงจะช่วยให้คุณเข้าใจ patterns และสามารถนำไปใช้กับปัญหาของตัวเองได้

### ตัวอย่าง 1: Calculator

```javascript
const calculator = {
  add: (a, b) => a + b,
  subtract: (a, b) => a - b,
  multiply: (a, b) => a * b,
  divide: (a, b) => {
    if (b === 0) return "Error: Cannot divide by zero";
    return a / b;
  },
  power: (a, b) => Math.pow(a, b),
  squareRoot: (a) => {
    if (a < 0) return "Error: Cannot get square root of negative";
    return Math.sqrt(a);
  },
};

console.log(calculator.add(10, 5)); // 15
console.log(calculator.subtract(10, 5)); // 5
console.log(calculator.multiply(10, 5)); // 50
console.log(calculator.divide(10, 5)); // 2
console.log(calculator.power(2, 8)); // 256
console.log(calculator.squareRoot(16)); // 4
```

### ตัวอย่าง 2: String Utilities

```javascript
const stringUtils = {
  capitalize: (str) => {
    return str.charAt(0).toUpperCase() + str.slice(1);
  },

  reverseString: (str) => {
    return str.split("").reverse().join("");
  },

  isPalindrome: (str) => {
    const cleaned = str.toLowerCase().replace(/[^a-z0-9]/g, "");
    return cleaned === stringUtils.reverseString(cleaned);
  },

  countVowels: (str) => {
    const vowels = "aeiouAEIOU";
    return str.split("").filter((char) => vowels.includes(char)).length;
  },

  removeSpaces: (str) => {
    return str.replace(/\s/g, "");
  },

  truncate: (str, length, suffix = "...") => {
    return str.length > length ? str.slice(0, length) + suffix : str;
  },
};

console.log(stringUtils.capitalize("hello")); // 'Hello'
console.log(stringUtils.reverseString("hello")); // 'olleh'
console.log(stringUtils.isPalindrome("racecar")); // true
console.log(stringUtils.countVowels("hello world")); // 3
console.log(stringUtils.removeSpaces("h e l l o")); // 'hello'
console.log(stringUtils.truncate("hello world", 5)); // 'hello...'
```

### ตัวอย่าง 3: Array Utilities

```javascript
const arrayUtils = {
  max: (arr) => Math.max(...arr),

  min: (arr) => Math.min(...arr),

  average: (arr) => {
    const sum = arr.reduce((a, b) => a + b, 0);
    return sum / arr.length;
  },

  flatten: (arr) => {
    return arr.reduce((flat, item) => {
      return flat.concat(Array.isArray(item) ? arrayUtils.flatten(item) : item);
    }, []);
  },

  unique: (arr) => [...new Set(arr)],

  chunk: (arr, size) => {
    const chunks = [];
    for (let i = 0; i < arr.length; i += size) {
      chunks.push(arr.slice(i, i + size));
    }
    return chunks;
  },

  shuffle: (arr) => {
    const shuffled = [...arr];
    for (let i = shuffled.length - 1; i > 0; i--) {
      const j = Math.floor(Math.random() * (i + 1));
      [shuffled[i], shuffled[j]] = [shuffled[j], shuffled[i]];
    }
    return shuffled;
  },
};

console.log(arrayUtils.max([1, 5, 3, 9, 2])); // 9
console.log(arrayUtils.min([1, 5, 3, 9, 2])); // 1
console.log(arrayUtils.average([1, 5, 3, 9, 2])); // 4
console.log(arrayUtils.flatten([1, [2, [3, 4]]])); // [1, 2, 3, 4]
console.log(arrayUtils.unique([1, 2, 2, 3, 3, 3])); // [1, 2, 3]
console.log(arrayUtils.chunk([1, 2, 3, 4, 5], 2)); // [[1,2], [3,4], [5]]
console.log(arrayUtils.shuffle([1, 2, 3, 4, 5])); // [3, 1, 5, 2, 4]
```

### ตัวอย่าง 4: Currency Converter

```javascript
function createCurrencyConverter(exchangeRates) {
  return function (amount, fromCurrency, toCurrency) {
    if (!exchangeRates[fromCurrency]) {
      return `Error: ${fromCurrency} not found`;
    }
    if (!exchangeRates[toCurrency]) {
      return `Error: ${toCurrency} not found`;
    }

    const amountInBase = amount / exchangeRates[fromCurrency];
    const result = amountInBase * exchangeRates[toCurrency];

    return parseFloat(result.toFixed(2));
  };
}

const rates = {
  USD: 1,
  EUR: 0.85,
  THB: 33.5,
  GBP: 0.73,
};

const convert = createCurrencyConverter(rates);

console.log(convert(100, "USD", "THB")); // 3350
console.log(convert(1000, "THB", "USD")); // 29.85
console.log(convert(50, "EUR", "GBP")); // 42.94
```

### ตัวอย่าง 5: Data Validation

```javascript
const validators = {
  isEmail: (email) => {
    const regex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
    return regex.test(email);
  },

  isPhoneNumber: (phone) => {
    const regex = /^[0-9]{10}$/;
    return regex.test(phone.replace(/\D/g, ""));
  },

  isStrongPassword: (password) => {
    return (
      password.length >= 8 &&
      /[a-z]/.test(password) &&
      /[A-Z]/.test(password) &&
      /[0-9]/.test(password) &&
      /[!@#$%^&*]/.test(password)
    );
  },

  isURL: (url) => {
    try {
      new URL(url);
      return true;
    } catch {
      return false;
    }
  },

  isEmpty: (value) => {
    return (
      value === null ||
      value === undefined ||
      (typeof value === "string" && value.trim() === "") ||
      (Array.isArray(value) && value.length === 0)
    );
  },
};

console.log(validators.isEmail("test@example.com")); // true
console.log(validators.isPhoneNumber("08-1234-5678")); // true
console.log(validators.isStrongPassword("Pass1234!")); // true
console.log(validators.isURL("https://example.com")); // true
console.log(validators.isEmpty("")); // true
```

---

## แบบฝึกหัด {#exercises}

### ระดับ Easy

#### 1. Simple Calculator Functions

```javascript
// สร้าง functions: add, subtract, multiply, divide
// แล้วเรียกใช้ทั้งหมด
```

#### 2. Temperature Converter

```javascript
// สร้าง functions แปลงอุณหภูมิ:
// - Celsius to Fahrenheit
// - Fahrenheit to Celsius
```

#### 3. Greeting Function

```javascript
// สร้าง function ที่รับ name และ time (morning/afternoon/evening)
// return greeting ที่เหมาะสม
```

### ระดับ Medium

#### 4. Number Checker

```javascript
// สร้าง functions:
// - isPrime(n) - ตรวจสอบจำนวนเฉพาะ
// - isEven(n)
// - isOdd(n)
// - isPositive(n)
// - isBetween(n, min, max)
```

#### 5. User Profile

```javascript
// สร้าง function ที่รับ object user
// return formatted string แสดงข้อมูล user
// เช่น: "John (john@example.com) - 25 years old"
```

#### 6. Array Processing

```javascript
// สร้าง functions:
// - findMax(arr)
// - findMin(arr)
// - calculateSum(arr)
// - filterEven(arr)
// - filterOdd(arr)
// - filterByValue(arr, value)
```

### ระดับ Hard

#### 7. Function Composition

```javascript
// สร้าง compose function ที่รวม functions
// const add2 = x => x + 2
// const multiply3 = x => x * 3
// const subtract1 = x => x - 1
// const result = compose(subtract1, multiply3, add2)(5)
```

#### 8. Debounce Function

```javascript
// สร้าง debounce function ที่ป้องกัน function ถูกเรียกหลายครั้ง
// ใช้สำหรับ search, resize events
```

#### 9. Memoization

```javascript
// สร้าง memoize function สำหรับ cache ผลลัพธ์
// ใช้สำหรับ fibonacci หรือ factorial
```

#### 10. Promise Chaining

```javascript
// สร้าง functions ที่ return Promise
// - fetchUser(id)
// - fetchPosts(userId)
// - fetchComments(postId)
// Chain ทั้งหมดเข้าด้วยกัน
```

---

## สรุป

- **Functions** ช่วยให้ code reusable และ maintainable
- **Declaration** hoisted, **Expression** และ **Arrow** ไม่ hoisted
- **Parameters** กำหนดเมื่อประกาศ, **Arguments** คือค่าที่ส่งเข้า
- **Return** ส่งค่ากลับ, ไม่มี return ก็ได้
- **Scope** มี global, function, และ block scope
- **Closure** ทำให้ function สามารถเข้าถึง outer scope ได้
- **Higher-Order Functions** รับหรือ return functions
- **Callbacks** ส่ง function เข้าไปเพื่อเรียกใช้ภายหลัง
- ใช้ meaningful names และ single responsibility
- หลีกเลี่ยง callback hell ด้วย Promises หรือ Async/Await

---

## แหล่งอ้างอิง

- [MDN - Functions](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Functions)
- [MDN - Arrow Functions](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions)
- [MDN - Closures](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Closures)

- [JavaScript.info - Functions](https://javascript.info/function-basics)
- [JavaScript.info - Arrow Functions](https://javascript.info/arrow-functions-basics)
- [JavaScript.info - Variable scope, closure](https://javascript.info/closure)
