ใน
บทที่ ๑๐
ได้เขียนถึงเรื่องการสร้างฟังก์ชันในจาวาสคริปต์แบบดั้งเดิมไปแล้ว
พอมาเป็นใน ES6 การสร้างฟังก์ชันมีความยืดหยุ่นขึ้น ทำอะไรได้หลากหลายและสะดวกมากขึ้น
ในบทนี้จะมาพูดถึงสิ่งที่ทำได้เพิ่มเติมมาจากเดิมในการสร้างฟังก์ชันใน ES6
การสร้างฟังก์ชันที่ไม่จำกัดจำนวนพารามิเตอร์
ในจาวาสคริปต์ก่อนที่จะมี ES6 นั้นถ้าหากต้องการสร้างฟังก์ชันที่รับพารามิเตอร์แบบจำนวนไม่จำกัด ปกติจะใช้ตัวแปร arguments
เช่น
var f = function() {
var len = arguments.length;
var i = 0;
var s = "";
while (i < len) {
s += "ตัวที่ " + i + " คือ " + arguments[i] + ", ";
i++;
}
alert(s);
};
f("ไก่", "ไข่", "ควาย"); // ได้ ตัวที่ 0 คือ ไก่, ตัวที่ 1 คือ ไข่, ตัวที่ 2 คือ ควาย,
แต่ว่าใน ES6 มีวิธีที่สะดวกกว่านั้นมาก คือการใช่จุด ๓ จุด ... แบบนี้นำหน้าพารามิเตอร์
แล้วพารามิเตอร์ตัวนั้นจะกลายเป็นแถวลำดับที่มีค่าเป็นอาร์กิวเมนต์ทั้งหมดที่รับเข้ามา ไม่ว่าจะมีกี่ตัวก็ตาม
หากจะเขียนตัวอย่างข้างต้นด้วยวิธีใหม่อาจเขียนได้แบบนี้
let f = function(...agumon) {
let len = agumon.length;
let i = 0;
let s = "";
while (i < len) {
s += "ตัวที่ " + i + " คือ " + agumon[i] + ", ";
i++;
}
alert(s);
};
f("ไก่", "ไข่", "ควาย"); // ได้ ตัวที่ 0 คือ ไก่, ตัวที่ 1 คือ ไข่, ตัวที่ 2 คือ ควาย,
จะเห็นว่าแค่เปลี่ยนจากการใช้ตัวแปร arguments เป็นใช้ตัวแปรที่กำหนดขึ้นเองโดยใส่ต่อจาก ... ในวงเล็บหลัง function
ซึ่งในที่นี้คือ agumon
ถึงแม้วิธีการใช้ตัวแปร arguments แบบเดิมก็ยังคงใช้ได้อยู่ แต่เมื่อเทียบกับวิธีใหม่ที่ใช้ ๓ จุดแบบนี้แล้วถือว่าด้อยกว่า
ทำให้ไม่จำเป็นต้องใช้อีกต่อไป เนื่องจากชื่อตัวแปรก็ยาวด้วย แล้วก็เป็นออบเจ็กต์ที่ไม่ใช่แถวลำดับจริงๆ
ไม่สามารถเอามาทำงานแบบแถวลำดับได้จริงๆ
ตัว arguments ไม่มีเมธอดอย่าง .join หรือ .forEach หรือ .map อีกทั้งไม่สามารถแสดงค่าได้โดยตรงโดย alert
ไม่ว่าจะทำอะไรก็จะใช้ต้องวนซ้ำด้วย for หรือ while เท่านั้น
แต่หากใช้ ๓ จุด สิ่งที่ได้มาจะเป็นข้อมูลแถวลำดับจริงๆ
let f = function (...agumon) {
if(agumon instanceof Array){
alert(agumon + " เป็น Array");
}
};
f("อา","กุ","มอน"); // ได้ อา,กุ,มอน เป็น Array
เมื่อเป็นแถวลำดับจึงสามารถใช้ map ได้ (รายละเอียดเรื่อง map อ่านใน
บทที่ ๒๗)
let f = function (...agapi) {
alert(
agapi.map(
function (x) {
return x + "เปลี่ยนร่าง";
}
)
);
};
f("อากุมอน", "กาบุมอน", "ปิโยมอน"); // ได้ อากุมอนเปลี่ยนร่าง,กาบุมอนเปลี่ยนร่าง,ปิโยมอนเปลี่ยนร่าง
แต่ถ้าเปลี่ยนมาใช้ arguments จะทำแบบนี้ไม่ได้
var f = function () {
alert(
arguments.map(
function (x) {
return x + "เปลี่ยนร่าง";
}
)
);
};
f("อากุมอน", "กาบุมอน", "ปิโยมอน"); // ได้ TypeError: arguments.map is not a function
นอกจากตัวพารามิเตอร์ที่เติม ๓ จุดแล้ว ถ้าหากใส่พารามิเตอร์อื่นไปในตำแหน่งก่อนหน้า
อาร์กิวเมนต์ที่ถูกใส่เข้าไปในลำดับก่อนหน้าก็จะไปแทนในพารามิเตอร์ และไม่รวมอยู่ในพารามิเตอร์ ๓ จุด
ส่วนตัวหลังจากนั้นจะอยู่ในพารามิเตอร์ ๓ จุด
ตัวอย่าง
let f = function (z, ...argu) {
alert(
argu.map(
function (x) {
return x + z;
}
)
);
};
f("หิวแล้ว", "โกมามอน", "ปาตามอน", "ไดโดมอน"); // ได้ โกมามอนหิวแล้ว,ปาตามอนหิวแล้ว,ไดโดมอนหิวแล้ว
การแตกค่าในแถวลำดับเพื่อใช้ในฟังก์ชัน
เดิมทีใน ES3 หรือ ES5 หากเราสร้างฟังก์ชันที่รับพารามิเตอร์หลายตัว ปกติเราจะต้องใส่ข้อมูลในวงเล็บไล่ไปทีละตัว
จะใส่แถวลำดับแทนไม่ได้ เช่น
var f = function (a,b,c) {
alert(a+b+c);
};
f(1, 2, 3); // ได้ 6
let arr = [1,2,3];
f(arr); // ได้ 1,2,3undefinedundefined
ในที่นี้ arr ถูกแทนลงตัวแปร a ซึ่งเป็นพารามิเตอร์ตัวแรกตัวเดียว ส่วน b กับ c ไม่ได้ค่าไปด้วยจึงเป็น undefined
แต่ใน ES6 นั้นหากมีแถวลำดับที่ใส่ข้อมูลอยู่
แล้วต้องการแตกให้ตัวแปรในแถวลำดับนั้นไปใช้เป็นอาร์กิวเมนต์แต่ละตัวของฟังก์ชันแยกกันก็ทำได้โดยเติม ๓ จุด ...
ไว้ข้างหน้าแถวลำดับ
เช่น
let arr = [2,3,4];
f(...arr); // ได้ 9
ถ้าเป็นใน ES3 หรือ ES5 อาจจำเป็นต้องไล่แยกข้อมูลในแถวลำดับทีละตัวด้วยตัวเอง
หรือไม่ก็ถ้าจะทำแบบนี้ได้อาจต้องใช้ฟังก์ชัน apply ซึ่งจะดูแล้วเข้าใจยากกว่า
f(arr[0], arr[1], arr[2]); // ได้ 9
f.apply(null, arr); // ได้ 9
การเติม ๓ จุดแบบนี้คล้ายกับการใช้ ๓ จุดในหัวข้อที่แล้ว คือใช้ใส่ในวงเล็บตอนนิยามฟังก์ชันขึ้น
แค่เปลี่ยนจากที่เดิมใช้กับพารามิเตอร์มาเป็นใช้กับอาร์กิวเมนต์
การกำหนดค่าตั้งต้นให้พารามิเตอร์ในฟังก์ชัน
ปกติแล้วเวลาที่ใช้ฟังก์ชันถ้าใส่ค่าให้ไม่ครบตามจำนวนพารามิเตอร์ ค่าตัวที่ขาดไปจะเป็น undefined
ใน ES3 หรือ ES5
ถ้าหากเราต้องการให้ค่าของตัวแปรที่ไม่ได้ใส่ไปนั้นเป็นค่าตามที่เรากำหนดไว้ให้เป็นค่าตั้งต้นก็จะต้องตั้งเงื่อนไขด้วย if
ว่าถ้าค่าเป็น undefined ให้มีการใส่ค่าตั้งต้นตามที่กำหนดเข้าไป เช่น
var f = function (chue, ayu) {
if(ayu===undefined){
ayu = 17;
}
alert("- ฉันชื่อ " + chue + " อายุ " + ayu + " ปี -")
};
f("ฮาจิเมะ"); // ได้ - ฉันชื่อ ฮาจิเมะ อายุ 17 ปี -
f("เยวี่ย", 323); // ได้ - ฉันชื่อ เยวี่ย อายุ 323 ปี -
แต่ว่าใน ES6 มีวิธีทำให้สามารถกำหนดค่าตั้งต้นให้พารามิเตอร์ได้โดยตรง โดยทำได้ง่ายแค่เติมเครื่องหมายเท่ากับ =
แล้วตามด้วยค่าตั้งต้นที่ต้องการ
ตัวอย่าง
let f = function (chue, ayu = 17) {
alert("- ฉันชื่อ " + chue + " อายุ " + ayu + " ปี -")
};
f("คาโอริ"); // ได้ - ฉันชื่อ คาโอริ อายุ 17 ปี -
f("ชิซึกุ", undefined); // ได้ - ฉันชื่อ ชิซึกุ อายุ 17 ปี -
f("ไอโกะ", 25); // ได้ - ฉันชื่อ ไอโกะ อายุ 25 ปี -
จะเห็นว่าถ้าไม่ได้ใส่ค่าหรือใส่เป็น undefined ก็จะได้ค่าตามค่าตั้งต้นที่ใส่ลงไป
ค่าตั้งต้นที่กำหนดไปนี้จะถูกใช้เมื่อไม่มีการป้อนค่าให้ หรือเมื่อป้อนค่าให้เป็น undefined
ดังนั้นหากต้องการให้พารามิเตอร์ที่อยู่ลำดับก่อนหน้าได้ค่าตั้งต้น แต่ต้องการกำหนดค่าให้ตัวที่อยู่หลังจากนั้นไปก็อาจใส่
undefined ให้
let f = function (a = 3, b = 7) {
alert("มีซูแบ็ต " + a + " ตัว อาร์บ็อก " + b + " ตัว");
};
f(); // ได้ มีซูแบ็ต 3 ตัว อาร์บ็อก 7 ตัว
f(5) // ได้ มีซูแบ็ต 5 ตัว อาร์บ็อก 7 ตัว
f(undefined, 4); // ได้ มีซูแบ็ต 3 ตัว อาร์บ็อก 4 ตัว
ค่าตั้งต้นอาจกำหนดโดยการใช้ค่าจากพารามิเตอร์อีกตัวที่อยู่ลำดับก่อนหน้าก็ได้ เช่น
let f = function (a, b = a * 2) {
alert("มีค้างคาว " + a + " ตัว งูเห่า " + b + " ตัว");
};
f(3); // ได้ มีค้างคาว 3 ตัว งูเห่า 6 ตัว
f(4, 10); // ได้ มีค้างคาว 4 ตัว งูเห่า 10 ตัว
แต่จะให้ค่าตัวก่อนหน้าขึ้นอยู่กับค่าข้างหลังไม่ได้ จึงสลับลำดับกันไม่ได้
let f = function (b = a * 2, a) {
alert("มีค้างคาว " + a + " ตัว งูเห่า " + b + " ตัว");
};
f(undefined, 3); // ได้ ReferenceError: can't access lexical declaration `a' before initialization
การสร้างฟังก์ชันแบบที่อาร์กิวเมนต์มีชื่อ
ฟังก์ชันที่สร้างแบบปกติตามวิธีที่เคยทำมานั้น เวลาที่ใช้จะต้องใส่ค่าลงไปตามลำดับพารามิเตอร์ที่วางไว้
ตัวอย่างเช่น ลองสร้างฟังก์ชันหาปริมาตรทรงสี่เหลี่ยม โดยมีตัวแปร ๓ ตัวคือกว้าง, ยาว และ สูง
let haParimat = function (kwang, yao, sung) {
let parimat = kwang * yao * sung;
alert("" + kwang + "×" + yao + "×" + sung + " = " + parimat);
};
haParimat(10, 12, 2) // ได้ 10×12×2 = 240
แต่ว่าแบบนี้อาจเข้าใจยากเวลาใช้ เพราะต้องจำว่าตัวแปรลำดับไหนคืออะไร
ดังนั้นเพื่อให้เข้าใจง่ายขึ้นอาจทำได้โดยป้อนค่าในรูปแบบของออบเจ็กต์ซึ่งมีพรอเพอร์ตีเป็นชื่อตัวแปรตามที่ต้องการ
let haParimat = function (kys) {
let parimat = kys.kwang * kys.yao * kys.sung;
alert("" + kys.kwang + "×" + kys.yao + "×" + kys.sung + " = " + parimat);
};
haParimat({sung: 2, kwang: 10, yao: 12}); // ได้ 10×12×2 = 240
พอทำแบบนี้แล้วก็จะดูง่ายขึ้น รู้ว่าตัวแปรไหนมีค่าเท่าไหร่ และไม่ขึ้นอยู่กับลำดับด้วย
เพียงแต่ว่าทำให้โค้ดดูซับซ้อนขึ้น
ใน ES6 มีวิธีเขียนให้ป้อนค่าเป็นออบเจ็กต์แบบนี้ได้โดยเขียนง่ายขึ้น คือใช้วงเล็บปีกกา { } คร่อมชื่อตัวแปร
let haParimat = function ({kwang, yao, sung}) {
let parimat = kwang * yao * sung;
alert("" + kwang + "×" + yao + "×" + sung + " = " + parimat);
};
haParimat({sung: 2, kwang: 10, yao: 12}); // ได้ 10×12×2 = 240
พอเขียนเป็นแบบนี้จะทำให้ค่าในออบเจ็กต์ที่ใส่ลงไปกลายเป็นตัวแปรในฟังก์ชันตามพรอเพอร์ตีที่ระบุไว้
และลำดับก็สามารถสลับกันได้ ไม่ต้องจำว่าต้องใส่ตัวไหนก่อน
ต่อให้ออบเจ็กต์ที่ใส่ไปมีพรอเพอร์ตีที่ไม่ได้ระบุไว้ในฟังก์ชันก็ไม่มีผลอะไร แค่ไม่ถูกนำมาคิด
haParimat({sung: 12, kwang: 70, yao: 100, nak: 600}); // ได้ 12×70×100 = 84000
หรือถ้าใส่ไม่ครบตัวที่ขาดไปก็จะกลายเป็น undefined
haParimat({sung: 15, kwang: 9}); // ได้ 9×undefined×15 = NaN
วิธีการนี้ก็สามารถกำหนดค่าตั้งต้นได้โดยการเติม = แล้วตามด้วยค่าตั้งต้นที่ต้องการ
โดยค่าตั้งต้นจะถูกใช้เมื่อออบเจ็กต์ที่ป้อนเข้ามาไม่มีพรอเพอร์ตีตัวนั้น
let haParimat = function ({ kwang, yao = 10, sung = 5 }) {
let parimat = kwang * yao * sung;
alert("" + kwang + "×" + yao + "×" + sung + " = " + parimat);
};
haParimat({ sung: 15, kwang: 9 }); // ได้ 9×10×15 = 1350
ในที่นี้ตัวแปร yao ไม่ได้ถูกป้อนเข้าไปจึงใช้ค่าตั้งต้น ส่วน sung มีการป้อนเข้าไปจึงใช้ค่าที่ป้อนเข้าไป
ไม่สนค่าตั้งต้น
หรือถ้าค่าเป็น undefined ค่าตั้งต้นก็จะถูกนำมาใช้เช่นกัน
haParimat({ sung: undefined, kwang: 9 }); // ได้ 9×10×5 = 450
การประกาศฟังก์ชันในแบบลูกศร
รูปแบบวิธีใหม่ในการสร้างฟังก์ชันได้ถูกเพิ่มเข้ามาใน ES6 คือการใช้ลูกศร => ในการสร้างฟังก์ชัน แทนที่จะเขียนว่า
function
ตัวอย่างเช่น เดิมทีอาจเขียนโดยใช้ function แบบนี้
let f = function (kai, khai) {
alert("ไก่ " + kai + " ตัวมีไข่ " + khai + " ฟอง");
};
f(20, 70); // ได้ ไก่ 20 ตัวมีไข่ 70 ฟอง
แต่สามารถเขียนใหม่แทนด้วย => ได้โดยเขียนแบบนี้
let f = (kai, khai) => {
alert("ไก่ " + kai + " ตัวมีไข่ " + khai + " ฟอง");
};
f(20, 70); // ได้ ไก่ 20 ตัวมีไข่ 70 ฟอง
การเขียนแบบนี้ดูกะทัดรัดสะดวกโดยเฉพาะเมื่อประกาศแล้วใช้ทันที เช่น
let ar = [3, 6, 8];
let s = ar.map((x) => { return "2×" + x + "=" + (x + x) });
alert(s); // ได้ 2×3=6,2×6=12,2×8=16
วงเล็บ () ด้านซ้ายของ => สามารถละได้ในกรณีที่พารามิเตอร์มีเพียงตัวเดียว เช่นในตัวอย่างที่แล้ว
เขียนฟังก์ชันใหม่ได้เป็น
let s = ar.map(x => { return "2×" + x + "=" + (x + x) });
การละวงเล็บทำได้แค่กรณีที่มีตัวแปร ๑ ตัวเท่านั้น แม้แต่กรณีที่ฟังก์ชันไม่มีพารามิเตอร์ก็ต้องใส่วงเล็บเปล่าไว้ ()
ตัวอย่างฟังก์ชันที่ไม่มีพารามิเตอร์
let f = () => { return "ສະບາຍດີ"};
alert(f()) // ได้ ສະບາຍດີ
การเขียนย่อฟังก์ชันแบบลูกศร
ฟังก์ชันที่ประกาศในแบบลูกศรหากมีโครสร้างเรียบง่ายและแค่ต้องการให้คืนค่าสามารถละวงเล็บปีกกา { } ได้ และไม่ต้องใส่ return
let f = (x, y) => x * y;
alert(f(2, 3)); // ได้ 6
แบบนี้มีค่าเท่ากับการเขียนว่า
let f = (x, y) => { return x * y };
เพียงแต่ว่ากรณีที่สิ่งที่ต้องการคืนค่านั้นเป็นออบเจ็กต์จะต้องใส่วงเล็บล้อมด้วย เช่นแบบนี้
let f = x => ({ 1: x });
alert(f(2)); // ได้ [object Object]
เพราะหากเขียนโดยไม่มีวงเล็บล้อมแบบนี้ กรอบวงเล็บปีกกา { } จะถูกตีความเป็นกรอบนิยามฟังก์ชัน แทนที่จะเป็นออบเจ็กต์ แบบนี้ก็จะเกิดข้อผิดพลาดขึ้น
let f = x => { 1: x }; // ได้ SyntaxError: unexpected token: ':'
ตัวแปร this เมื่อประกาศฟังก์ชันในแบบลูกศร
โดยภาพรวมแล้วฟังก์ชันที่สร้างโดยใช้ลูกศรจะมีลักษณะเหมือนกับฟังก์ชันที่สร้างด้วยคำสั่ง function()
แต่ก็มีข้อแตกต่างบางอย่าง ที่สำคัญก็คือ ตัวแปร this เมื่อใช้ฟังก์ชันในโครงสร้างออบเจ็กต์
ดังที่ได้อธิบายไปใน
บทที่ ๑๙ this
เป็นตัวแปรพิเศษซึ่งจะแทนอะไรขึ้นอยู่กับว่าอยู่ที่ไหน
ปกติถ้าใช้นอกฟังก์ชัน this จะแทบออบเจ็กต์ global แต่ถ้าหากฟังก์ชันถูกเรียกใช้ในฐานะเมธอดภายในออบเจ็กต์ กรณีนี้ this จะแทนตัวออบเจ็กต์นั้น เช่น
let krapuk1 = {
ngoen: 10000,
bokNgoen: function() {
alert("มีเงิน "+this.ngoen);
}
};
krapuk1.bokNgoen() // ได้ มีเงิน 10000
แต่ถ้าเป็นฟังก์ชันที่สร้างด้วยลูกศร this จะไม่ถูกแทนด้วยออบเจ็กต์นั้น
เช่น ลองเขียนฟังก์ชันเหมือนเดิมแต่เปลี่ยนเป็นใช้ลูกศร
let krapuk2 = {
ngoen: 10000,
bokNgoen: () => {
alert("มีเงิน "+this.ngoen);
}
};
krapuk2.bokNgoen() // ได้ มีเงิน undefined
ในที่นี้ this จะไม่แทนตัวออบเจ็กต์ที่เรียก ดังนั้น this ก็จะไปแทนสิ่งเดิมทีควรเป็น this อยู่ ซึ่งในที่นี้ก็คือแทนออบเจ็กต์
global ดังนั้นเมื่อหาพรอเพอร์ตี .ngoen จึงไม่พบ และได้ undefined ไป
หากมีการใช้ฟังก์ชันด้านในฟังก์ชันหรือเมธอดจะซับซ้อนขึ้นไปอีก และจะทำให้เกิดความสับสนได้ง่าย จึงต้องทำความเข้าใจให้ดี
ตรงนี้จะเห็นความแตกต่างระหว่างการสร้างฟังก์ชันด้วย function กับด้วยการใช้ลูกศร
ตัวอย่างเช่น สร้างออบเจ็กต์ตัวหนึ่งให้มีเมธอดอยู่ และภายในเมธอดนั้นก็มีการเรียกใช้ฟังก์ชัน โดยทั้งเมธอดและฟังก์ชันด้านในใช้วิธีการนิยามด้วยคำสั่ง function แบบนี้
let krapukB = {
ngoen: 7,
toemNgoen: function (ar) {
ar.forEach(function (x) {
this.ngoen += x; // this ในที่นี้คือ global
})
alert(this.ngoen); // this ในที่นี้คือ krapukB
}
};
krapukB.toemNgoen([20, 500, 1000]); // ได้ 7
ในที่นี้ออบเจ็กต์ krapukB มีพรอเพอร์ตีคือ ngoen (เงิน) คือจำนวนเงินที่มีอยู่ และเมธอด toemNgoen (เติมเงิน)
สำหรับเติมเงินใส่เพิ่มเข้าไป โดยจะรับค่าเป็นแถวลำดับซึ่งมีตัวเลขอยู่หลายตัว
แล้วเอาเลขในนั้นมาบวกเข้าไปในจำนวนเงินเดิมทีละตัว แล้วสุดท้ายจึงใช้ alert แสดงจำนวนเงินหลังเติมเสร็จ
แต่พอเขียนแบบนี้จะเห็นว่าผลไม่ได้ตามที่ต้องการ เงินเริ่มต้นมี 7 แต่หลังจากที่เติมเงินโดยใช้เมธอด .forEach
ไปเงินกลับไม่เพิ่มขึ้น ทั้งที่ในฟังก์ชันใน forEach มีการสั่งให้บวกเงินเพิ่มเข้าไปใน this.ngoen
ที่เป็นแบบนี้ก็เพราะว่า this ในที่นี้อยู่ในฟังก์ชันซึ่งถูกสร้างขึ้นมาใหม่ใน forEach จึงไม่ได้แทนตัวออบเจ็กต์ krapukB
ซึ่งเป็นตัวเรียก แต่แทนตัวออบเจ็กต์ global ดังนั้นการบวก this.ngoen จึงไม่มีผลกับเงินใน krapukB
ทำให้ไม่สามารถเข้าถึงตัวออบเจ็กต์นั้นผ่าน this ได้
ต้องแก้ปัญหาโดยการฝากให้ตัวแปรอื่นแทนออบเจ็กต์นั้นก่อนที่จะเข้าฟังก์ชัน เช่นทำแบบนี้
let krapukC = {
ngoen: 7,
toemNgoen: function (ar) {
let cette = this; // สร้างตัวแปรใหม่ใช้แทน this ชั่วคราว
ar.forEach(function (x) {
cette.ngoen += x; // ตัวแปรชั่วคราว cette แทน krapukC
})
alert(this.ngoen); // this ในที่นี้คือ krapukC
}
};
krapukC.toemNgoen([20, 500, 1000]); // ได้ 1527
ในที่นี้ใช้ตัวแปร cette แทน this แล้วจึงเอา cette นั้นมาใช้ในฟังก์ชันด้านใน แบบนี้ cette ก็จะแทนตัวออบเจ็กต์นั้นแทนเลย
จึงเข้าถึงตัวออบเจ็กต์นั้นผ่านตัวแปรนี้ได้ ทำให้การเพิ่มเงินคราวนี้สำเร็จ
การเขียนแบบนี้อาจดูยุ่งยาก แต่สามารถทำให้ง่ายขึ้นได้โดยใช้การนิยามฟังก์ชันแบบลูกศร เพราะวิธีนี้จะทำให้ this
ไม่ถูกเปลี่ยนความหมายไป
เมื่อเขียนแทนด้วย => จะกลายเป็นแบบนี้
let krapukD = {
ngoen: 7,
toemNgoen: function (ar) {
ar.forEach(x => {
this.ngoen += x; // this ในที่นี้คือ krapukD
})
alert(this.ngoen); // this ในที่นี้คือ krapukD
}
};
krapukD.toemNgoen([20, 500, 1000]); // ได้ 1527
จะเห็นว่าพอใช้ลูกศรแทนแล้ว ในที่นี้ this ด้านใน forEach เองก็ถือเป็น this ตัวเดียวกับนอก forEach คือแทนตัวออบเจ็กต์
krapukD เหมือนกัน ไม่จำเป็นต้องเอา this ไปฝากไว้ที่ไหน
อย่างไรก็ตาม ตัวเมธอด toemNgoen จะใช้เป็นลูกศรแทนไม่ได้ เพราะถ้าใช้ลูกศรสร้างจะทำให้ this ในนั้นไม่ได้แทนตัวออบเจ็กต์
แต่ก็กลับจะไปแทนตัว global แทน
let krapukF = {
ngoen: 7,
toemNgoen: ar => {
ar.forEach(x => {
this.ngoen += x; // this ในที่นี้คือ global
})
alert(this.ngoen); // this ในที่นี้คือ global
}
};
krapukF.toemNgoen([20, 500, 1000]); // ได้ NaN
คราวนี้ this ทั้งด้านในและนอก forEach ก็กลายเป็นแทนออบเจ็กต์ global ทั้งหมด จึงไม่มีพรอเพอร์ตี .ngoen
และทำให้ได้ค่าออกมาเป็น NaN
จากตัวอย่างนี้จะเห็นได้ถึงความสำคัญในการแยกใช้การนิยามฟังก์ชัน ๒ วิธี
หากเข้าใจได้ดีแล้วก็จะสามารถเขียนโค้ดได้สั้นและเข้าใจง่ายและไม่ผิดพลาดโดยไม่รู้ตัว
ใส่ , หลังพารามิเตอร์ตัวสุดท้าย [ES2017]
มีความสามารถจุกจิกเล็กๆน้อยๆที่ถูกเพิ่มเข้ามาใน ES2017 นั่นคือการที่สามารถใส่ ,
ลงไปหลังจากพารามิเตอร์ตัวสุดท้ายตอนประกาศสร้างฟังก์ชันได้
let f = function (a, b,) {
alert("a=" + a + " b=" + b);
};
f(50,60); // ได้ a=50 b=60
ในขณะที่ถ้าทำแบบนี้ในเวอร์ชันก่อนหน้านี้ก็จะเกิดข้อผิดพลาดขึ้นมา ต้องเขียนเป็นแค่ function (a, b) ไม่มี ,
ต่อท้าย
การที่สามารถเติม , ข้างหลังได้นี้อาจไม่ได้ทำให้เขียนง่ายขึ้น แต่อาจมีประโยชน์ในบางเวลา
เช่นเมื่อเตรียมจะใส่พารามิเตอร์ตัวอื่นเพิ่มต่อไปทีหลัง