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']
การทำงานของตัวอย่างนี้ 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
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();
จากตัวอย่างด้านบน หลังจาก 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();
ใน 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);
}
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();
เอาละครับคงพอเห็นแนวทางการใช้งานและประโยชน์ต่างๆ ของ Arrow function กันบ้างแล้วนะ บทความนี้ก็คงขอจบไว้เพียงเท่านี้ก่อน ขอให้ติดตามและสนุกกับการเรียนรู้กันต่อไปนะครับ
Top comments (0)