หัวข้อ 1: ตัวแปร var, let, const และขอบเขต Scope

คำจำกัดความ

ตัวแปร (Variable) คือชื่อที่ใช้เก็บค่าเพื่อนำไปใช้งานภายหลัง ส่วน Scope คือขอบเขตที่ตัวแปรสามารถถูกเข้าถึงได้

%%{init: {"theme": "base", "themeVariables": {"primaryColor": "#458588", "primaryTextColor": "#fbf1c7", "primaryBorderColor": "#fabd2f", "lineColor": "#a89984", "secondaryColor": "#b8bb26", "tertiaryColor": "#d3869b", "background": "#282828", "mainBkg": "#3c3836", "textColor": "#ebdbb2"}}}%%
flowchart TD
  A["Variable Declaration
การประกาศตัวแปร"] --> B["var
Function Scope"] A --> C["let
Block Scope"] A --> D["const
Block Scope + assign once"] B --> E["Hoisting
ถูกยกประกาศขึ้น"] C --> F["TDZ
Temporal Dead Zone"] D --> F

เปรียบเทียบ var, let, const

คำสั่ง Scope Hoisting เปลี่ยนค่าได้ ประกาศซ้ำใน scope เดิม
var Function Scope มี ได้ ได้
let Block Scope มีแต่ติด TDZ ได้ ไม่ได้
const Block Scope มีแต่ติด TDZ ไม่ได้เมื่อเป็น binding ไม่ได้

var: Function Scope และปัญหาที่ควรหลีกเลี่ยง

var มีขอบเขตระดับฟังก์ชัน ไม่ใช่ระดับ block และถูก hoist ทำให้อ่านโค้ดยากในหลายกรณี

function demoVar() {
  // var ถูก hoist ทำให้เข้าถึงก่อนประกาศได้ แต่ค่าเป็น undefined
  console.log(score); // undefined

  if (true) {
    var score = 80;
  }

  // var ไม่ถูกจำกัดใน if block
  console.log(score); // 80
}

// ตัวอย่างการใช้งาน
demoVar();

let: Block Scope สำหรับค่าที่เปลี่ยนได้

let เหมาะกับตัวแปรที่ต้องเปลี่ยนค่า และมีขอบเขตตาม block เช่น { ... }

function demoLet() {
  let total = 0;

  for (let i = 1; i <= 3; i++) {
    // i อยู่ใน scope ของ for block
    total += i;
  }

  console.log(total); // 6
}

// ตัวอย่างการใช้งาน
demoLet();

const: Block Scope สำหรับค่าคงที่

const ต้อง assign ค่าทันที และไม่สามารถเปลี่ยน binding ไปชี้ค่าใหม่ได้

const passingScore = 50;
const student = { name: "Ana", score: 82 };

// Object ที่ประกาศด้วย const ยังแก้ property ได้
student.score = 90;

console.log(passingScore); // 50
console.log(student); // { name: "Ana", score: 90 }

Global, Function และ Block Scope

const appName = "Grade App"; // Global Scope

function calculate() {
  const score = 75; // Function Scope

  if (score >= 50) {
    const result = "ผ่าน"; // Block Scope
    console.log(result);
  }
}

calculate();
console.log(appName);

Temporal Dead Zone (TDZ)

TDZ คือช่วงตั้งแต่เริ่ม block จนถึงบรรทัดที่ประกาศ let หรือ const ซึ่งตัวแปรยังถูกเข้าถึงไม่ได้

function demoTDZ() {
  // console.log(name); // ReferenceError
  const name = "Web Programming";
  console.log(name);
}

demoTDZ();

Closure

Closure คือฟังก์ชันที่จดจำ scope ของตัวเองได้ แม้ถูกเรียกใช้นอก scope เดิม

function createCounter() {
  let count = 0;

  return function increase() {
    // increase จำตัวแปร count ได้
    count += 1;
    return count;
  };
}

const counter = createCounter();
console.log(counter()); // 1
console.log(counter()); // 2
console.log(counter()); // 3

สมการจำนวนครั้งที่เพิ่มค่า

countn = count0 + n

โดยที่ countₙ คือค่าหลังเรียกฟังก์ชัน n ครั้ง, count₀ คือค่าเริ่มต้น, และ n คือจำนวนครั้งที่เรียกฟังก์ชัน

แบบทดสอบหลังเรียน

  1. เหตุใดจึงควรหลีกเลี่ยง var ในโค้ดสมัยใหม่
  2. let และ const มี scope แบบใด
  3. TDZ คืออะไร
  4. Closure มีประโยชน์อย่างไร
  5. ทำไม object ที่ประกาศด้วย const ยังแก้ property ได้

กลับสัปดาห์ที่ 4