DEV Community

iammen
iammen

Posted on

10 เรื่องของ ES6 ที่คุณควรรู้ไว้ (ตอนที่ 4 Arrow Functions)

10 เรื่องของ ES6 ที่คุณควรรู้ไว้ (ตอนที่ 4 Arrow Functions)

สวัสดีครับท่านผู้สนใจในการเขียนโปรแกรมด้วยภาษา JavaScript ทุกท่าน บทความนี้เป็นตอนที่ 4 ในซี่รีย์ชุด 10 เรื่องของ ES6 ที่คุณควรรู้ไว้ ครั้งนี้ผมจะมาแบ่งปันกับทุกๆ คนในเรื่อง Arrow Functions กัน

Arrow function เป็นรูปแบบ syntax ที่ใช้งานสำหรับ function โดยเฉพาะ ตัว syntax ที่ใช้จะมีลักษณะคล้ายลูกศรคือ => ประโยชน์หลักๆ ของมันก็คือ ทำให้รูปแบบการเขียน function ใน JavaScrip ดูสั้นกระชับมากขึ้น รวมทั้งความสามารถในการจัดการกับ this keyword ของมันก็ทำให้เราทำความเข้าใจได้ง่ายขึ้นเช่นกัน มาลองดูตัวอย่างการใช้งานของมันกันเลย

เขียน function ให้กระชับด้วย Arrow function

ตัวอย่างที่กำลังจะแสดงเราจะประกาศตัวแปร array ชื่อ aHero ซึ่งมันจะเก็บข้อมูล string แบบตัวพิมพ์เล็กทั้งหมดเอาไว้ 1 ชุด จากนั้นเราจะลองใช้งาน arrow function ร่วมกับ map method (map เป็น built-in method ของ Array object ใน JavaScript) เพื่อเปลี่ยนข้อความใน array เป็นตัวพิมพ์ใหญ่ทั้งหมดด้วย toUpperCase method อีกที อธิบายมากเดี๋ยวจะงง มาดูตัวอย่างกันดีกว่า

// ประกาศตัวแปร array
var aHero = ['superman', 'spiderman', 'batman'];

// ใช้ map method ใน ES5 เดิม
var es5Output = aHero.map(function(h) { 
  return h.toUpperCase()
});

// ใช้ map method ใน ES6 ด้วย arrow function
var es6Output = aHero.map( h => h.toUpperCase() );

console.log(es5Output);  // ['SUPERMAN', 'SPIDERMAN', 'BATMAN']
console.log(es6Output);  // ['SUPERMAN', 'SPIDERMAN', 'BATMAN']
Enter fullscreen mode Exit fullscreen mode

การทำงานของตัวอย่างนี้ map method จะรับ parameter เข้าไป 1 ตัวซึ่งคือฟังก์ชั่นแบบไม่มีชื่อหรือที่เรียกกันว่า anonymous function และ function นี้ก็จะรับ parameter อีก 1 ตัวที่เราตั้งชื่อว่า h ซึ่งตัวแปร h นี้จะเก็บข้อมูล string ซึ่งก็จะคือข้อมูลในแต่ละตำแหน่งที่เก็บอยู่ในตัวแปร aHero นั้นเอง สุดท้ายในส่วน body ของ function นี้ก็จะทำการเปลี่ยนข้อความ string ให้เป็นตัวพิมพ์ใหญ่ด้วย toUpperCase method และทำการคืนค่ามันออกมา

จะสังเกตว่าเมื่อเราใช้ arrow function เราจะสามารถละการเขียน function และ return syntax ไปได้เลย ทำให้ code ที่ได้ดูสั้นกระชับมากขึ้น

ต่อไปมาลองดูตัวอย่างการใช้งาน arrow function แบบใช้ parameter หลายๆ ตัวกันบ้าง

// แบบ ES5
var es5Multiply = function(x, y) {
 return x * y;
}
alert(es5Multiply(2, 5)); // 10

// แบบ ES6
var es6Multiply = (x, y) => { return x * y };
alert(es6Multiply(4, 10)); // 40
Enter fullscreen mode Exit fullscreen mode

this keyword ใน JavaScript

จากที่ทราบกันว่าในทุกๆ function จะมีการประกาศ this ของมันเองขึ้นมาใช้งาน ซึ่งถ้าใครเคยผ่านการเขียนโปรแกรมด้วยภาษา C# หรือ Java มาก่อนก็คงพอจะเข้าใจว่า this keyword นี้จะเปรียบเสมือนเป็นตัวแทนของ object ที่กำลังทำงานอยู่ ทำให้เราสามารถใช้ this เพื่อเข้าถึงตัวแปรหรือว่า function ของ object นั้นได้

แต่แนวคิดนี้กลับใช้ไม่ได้กับเจ้า this ใน JavaScript เพราะ this ใน JavaScript ที่ถูกสร้างขึ้นมานั้นจะมีสถานะการทำงานขึ้นอยู่กับ Execution context ก่อนหน้าที่ function นั้นถูกเรียกใช้งาน อธิบายแบบนี้คงจะต้องงงกันเป็นแน่ มาดูตัวอย่างกันดีกว่า

function displyContext() {
 this.name = 'จุดนี้คือ global context';
 console.log(this);
}

// ผลลัพธ์ที่ได้คือจะพิมพ์ this ในตำแหน่ง window object
// เพราะ function ถูกเรียกใช้งานในระดับ global context
displyContext();

var obj = {
 name: 'จุดนี้คือ function context',
 displyContext: function() {
  console.log(this);
 }
};

// ผลลัพธ์ที่ได้คือจะพิมพ์ this ในตำแหน่งของตัวแปร obj
// เพราะ function ถูกเรียกใช้งานภายในตัวแปร obj
obj.displyContext();

var global = obj.displayContext;
global();
Enter fullscreen mode Exit fullscreen mode

จากตัวอย่างด้านบน หลังจาก function ชื่อ displyContext ถูกเรียกใช้งานเราจะได้ผลลัพธ์แรกที่ถูกพิมพ์ออกมาเป็น this ในระดับ window object ซึ่งก็เพราะว่า execution context ก่อนหน้าที่ function นี้จะถูกเรียกใช้งานมันคือ global context ซึ่งบน browser ตัว global context ที่ว่าก็คือ window object นั้นเอง ทำให้ this ที่ถูกสร้างขึ้นจะอ้างถึง window object ในทันที ทีนี้ลองมาเดาดูสิครับว่าตัวแปร name ที่ประกาศภายใน function นี้จะอยู่ภายใต้ window object ด้วยหรือไม่ ไปทดลองกันดูนะครับ

ลำดับถัดมาเป็นการเรียก function ชื่อ displyContext เหมือนเดิม แต่คร่าวนี้ displyContext จะทำงานเหมือนเป็น method ของ object ที่ชื่อว่า obj อีกที ซึ่งหลังจากที่ function นี้ถูกใช้งาน เราจะได้ผลลัพธ์ที่พิมพ์ this ออกมาในระดับ obj object แทน ไม่ใช่ window object แล้วนะครับตอนนี้ เหตุที่เป็นแบบนี้ก็เพราะว่า execution context ก่อนหน้าที่ displyContext จะถูกเรียกใช้งานก็คือตัว obj object นั่นเอง

และสุดท้ายคือการสร้างตัวแปรขึ้นมาอีกตัวชื่อ global แล้วกำหนดตำแหน่งอ้างอิงของ displyContext ของตัวแปร obj ให้กับมัน จากนั้นก็ทำการเรียกใช้งานฟังก์ชั่น global แต่คราวนี้ execution context จะเปลี่ยนจาก obj object เป็น window object เช่นเดิม แน่นอนครับสาเหตุก็เพราะ execution context ก่อนหน้าที่จะเรียกฟังก์ชั่น global ใช้งานคือ window object นั่นเอง

การใช้งาน this keyword ในยุคก่อน Arrrow function

จากตัวอย่างก่อนหน้าคุณคงเห็นแล้วว่า การใช้งาน this keyword ได้อย่างถูกต้องนั้น เราจำเป็นต้องเข้าใจในเรื่อง execution context กันเสียก่อน ไม่อย่างนั้นอาจจะทำให้เกิดความสับสนได้ มาลองดูอีกตัวอย่างหนึ่งที่จะแสดงถึงปัญหาของการใช้งาน this keyword กัน

function MyHero() {
 // ณ จุดนี้เป็น MyHero constructor จะเป็นจุดที่สร้าง this ขึ้นมาใช้งาน 
 // เพื่อทำหน้าที่แทน MyHero object เอง
 this.fight = 0;

 setInterval(function fighting() {
  // this นี้จะอ้างอิงกับ window object
  this.fight++;
 }, 5000);
}

var hero = new MyHero();
Enter fullscreen mode Exit fullscreen mode

ใน non-strict mode นั้น เมื่อฟังก์ชั่น fighting ถูกเรียกใช้งานมันก็จะสร้าง this ของมันเองขึ้นมาใช้งาน แต่ this ที่มันสร้างมานี้จะอ้างอิงกับ window object แทนไม่ใช่ this ของตัวแปร MyHero อย่างที่คุณคิดกัน จากปัญหานนี้ใน ES5 จึงก็มีเทคนิคการจัดการกับ this เพื่อใช้ในการแก้ปัญหานี้ มาดูตัวอย่าง

function MyHero() {
 var that = this; // กำหนด this ให้กับตัวแปร that
 that.fight = 0;

 setInterval(function fighting() {
  // เมื่อ fighting() ทำงานมันก็จะสามารถใช้งานตัวแปร that 
  // ซึ่งจริงๆ ก็คือ this ของ MyHero ได้อย่างถูกต้อง
  that.fight++;
  }, 5000);
}
Enter fullscreen mode Exit fullscreen mode

Arrow function ผู้พิชิต this keyword

หลังจาก Arrow function ได้ถูกนำมาให้งานใน ES6 ปัญหาน่าปวดหัวต่างๆ เหล่านี้กลับหมดไปทันที เนื่องจากมันมีความฉลาดพอที่จะรู้ว่า execution context ที่เราต้องการใช้งานจริงนั้นคือจุดไหน มาดูตัวอย่างเลย

function MyHero(){
 this.fight = 0;

 setInterval(() => {
  // this ที่ถูกเรียกใช้งานนี้จะอ้างอิงกับ MyHero object ในทันที
  this.fight++;
 }, 5000);
}

var h = new MyHero();
Enter fullscreen mode Exit fullscreen mode

เอาละครับคงพอเห็นแนวทางการใช้งานและประโยชน์ต่างๆ ของ Arrow function กันบ้างแล้วนะ บทความนี้ก็คงขอจบไว้เพียงเท่านี้ก่อน ขอให้ติดตามและสนุกกับการเรียนรู้กันต่อไปนะครับ

Top comments (0)