บทนี้จะแนะนำความสามารถใน ES5 ที่เหลือที่ไม่ได้กล่าวถึงในบทก่อนๆ
โหมดเคร่งครัด
ปกติเวลาเขียนโปรแกรมในจาวาสคริปต์นั้นมีความเป็นอิสระในการเขียนมากทีเดียว
เพียงแต่ว่าก็มีรูปแบบการเขียนบางอย่างที่แม้จะเขียนได้โดยไม่เกิดข้อผิดพลาดอะไร
แต่ก็ไม่แนะนำให้ใช้ เพราะอาจทำให้เกิดปัญหาบางอย่าง เช่นในด้านความปลอดภัย
เพื่อป้องกันโค้ดประเภทที่สามารถเขียนได้ แต่ไม่ควรเขียน ใน ES5
จึงมีการเพิ่มโหมดเคร่งครัด (strict) ขึ้นมา
เป็นโหมดที่เมื่อเปิดแล้วจะไม่ปล่อยให้ใช้โค้ดที่ไม่ควรเขียนเหล่านั้น
โหมดนี้จะทำให้เมื่อเขียนโค้ดในแบบที่ไม่ควรเขียนก็จะเกิดข้อผิดพลาด (error) ขึ้น
แล้วโปรแกรมก็จะหยุดไป
การเปิดโหมดนี้อาจทำได้ทั้งเปิดให้มีผลทั้งโปรแกรม
กับเปิดใช้เฉพาะในฟังก์ชันก็ได้
เมื่อเปิดแล้ว การกระทำต่อไปนี้จะทำให้เกิดข้อผิดพลาด
- ประกาศตัวแปรโดยไม่ใช้ var
- ใช้ชื่อพารามิเตอร์ในฟังก์ชันซ้ำ
- ป้อนค่าทับตัวแปร arguments ในฟังก์ชัน
- เข้าถึง arguments.callee
- ป้อนค่าเข้า undefined
- ใช้ with
-
ละเมิดข้อจำกัดการเปลี่ยนแปลงของตัวออบเจ็กต์ (บทที่ ๒๕)
-
ละเมิดข้อจำกัดการเปลี่ยนแปลงของพรอเพอร์ตี (บทที่ ๒๖)
นอกจากนี้ การกระทำเหล่านี้จะทำให้ผลลัพธ์เปลี่ยนไปจากเดิม
- ตัวแปรที่ประกาศใน eval จะใช้นอก eval ไม่ได้
-
this เมื่อใช้ในฟังก์ชันนอกออบเจ็กต์จะไม่แทนตัว global แต่จะกลายเป็น
undefined
หลายอย่างที่กล่าวถึงในนี้จริงๆไม่เคยพูดถึงในบทที่ผ่านๆมาเลยด้วยซ้ำ เช่น with
เพราะจริงๆแล้วเป็นสิ่งที่ไม่ได้ควรจะใช้อยู่แล้ว
เลยไม่ได้จำเป็นจะต้องยกมาพูดถึงมากนัก
วิธีการเปิดโหมดเคร่งครัดทั้งตัวโปรแกรมนั้นทำได้โดยใส่ "use strict"
ตอนเริ่มโปรแกรม
ตัวอย่าง
ประกาศตัวแปรโดยไม่ใช้ var
"use strict";
a = 1; // ได้ ReferenceError: assignment to undeclared variable a
ชื่อพารามิเตอร์ในฟังก์ชันซ้ำ
"use strict";
var f = function(x,x){} // ได้ SyntaxError: duplicate formal argument x
ป้อนค่าให้ตัวแปร arguments ในฟังก์ชัน
"use strict";
var f = function(){
arguments = 1 // ได้ SyntaxError: 'arguments' can't be defined or assigned to in strict mode code
}
การป้อนค่าให้ undefined นั้นแต่ไหนแต่ไรเป็นสิ่งที่ถึงทำไปก็ไม่ได้มีผลอะไร
เพราะ undefined เป็นค่าที่เขียนทับไม่ได้ แต่ก็ไม่เกิดข้อผิดพลาดขึ้น
แต่พอเปิดโหมดนี้แล้วพอทำจะเกิดข้อผิดพลาด
"use strict";
undefined = 1; // ได้ TypeError: "undefined" is read-only
ออบเจ็กต์ที่ freeze ไว้ ปกติถ้าพยายามไปแก้ไขค่าจะแค่ไม่เกิดอะไรขึ้น
แต่ถ้าเปิดโหมดนี้จะทำให้เกิดข้อผิดพลาดขึ้นทันที
"use strict";
var obj = { a: 1 };
Object.freeze(obj);
obj.a = 2; // ได้ TypeError: "a" is read-only
delete obj.a; // ได้ TypeError: property "a" is non-configurable and can't be deleted
obj.b = 3; // ได้ TypeError: can't define property "b": Object is not extensible
ข้อจำกัดในตัวพรอเพอร์ตี ซึ่งได้จากการใช้ Object.create หรือ
Object.defineProperty ก็เช่นกัน
"use strict";
var obj = Object.create(
{},
{
a: { value: 1, writable: false }
}
);
obj.a = 3; // ได้ TypeError: "a" is read-only
เมื่อใช้ eval ตัวแปรที่ประกาศใน eval จะใช้ข้างนอก eval ไม่ได้
"use strict";
eval("var a = 1");
alert(a); // ได้ ReferenceError: a is not defined
เมื่อใช้ this ในฟังก์ชันที่ไม่ใช่อยู่ในออบเจ็กต์จะได้ไม่ชี้ถึงตัว global
แต่ละได้ undefined
"use strict";
var f = function() {
alert(this);
};
f(); // ได้ undefined
โหมดเคร่งครัดภายในฟังก์ชัน
ปกติถ้าใส่ "use strict" ตอนต้นโปรแกรมจะเป็นการเปิดให้มีผลทั้งโปรแกรม
แต่หากต้องการให้เปิดโหมดแค่ในฟังก์ชันให้ใส่ "use strict"
ตอนเริ่มฟังก์ชัน
var f = function() {
"use strict";
undefined = 1;
};
undefined = 1; // ไม่เกิดข้อผิดพลาด
f(); // TypeError: "undefined" is read-only
เมธอด trim
เมธอด trim
ในข้อมูลชนิดสายอักขระจะสามารถทำการตัดช่องว่างหรือเว้นบรรทัดที่อยู่หน้าหรือหลังสุดทั้งหมดได้
var s = " ทริม ";
alert('"' + s + '"'); // ได้ " ทริม "
alert('"' + s.trim() + '"'); // ได้ "ทริม"
เมธอด indexOf และ lastIndexOf ในแถวลำดับ
เดิมทีเมธอด indexOf และ lastIndexOf เป็นเมธอดที่มีอยู่ในข้อมูลชนิดสายอักขระ
ได้กล่าวถึงไปแล้วใน
บทที่ ๑๓
แต่ใน ES5 เมธอดนี้สามารถใช้ในแถวลำดับได้ด้วย
indexOf จะทำการค้นหาข้อมูลในแถวลำดับว่ามีตัวที่เราต้องการอยู่ในตำแหน่งไหน
แล้วจะคืนค่าตำแหน่งนั้นมา โดยไล่หาจากซ้ายสุด (ตำแหน่ง 0)
ถ้าเจออันไหนที่ตรงก็คืนเลขค่าลำดับตำแหน่งนั้น
ส่วน lastIndexOf จะเหมือนกัน แค่เริ่มไล่หาจากขางขวาสุดก่อน
หากค้นหาแล้วไม่เจอเลยจะได้ -1
var pk = ["ฮาเน็กโกะ", "โปโปกโกะ", "วาตักโกะ", "โปโปกโกะ", "ฮาเน็กโกะ"];
alert(pk.indexOf("ฮาเน็กโกะ")); // ได้ 0
alert(pk.indexOf("โปโปกโกะ")); // ได้ 1
alert(pk.lastIndexOf("โปโปกโกะ")); // ได้ 3
alert(pk.indexOf("โมโกโกะ")); // ได้ -1
สามารถกำหนดจุดเริ่มต้นการค้นได้โดยใส่อาร์กิวเมนต์ตัวที่ ๒ ลงไป
ตัวที่อยู่ตำแหน่งก่อนหน้าเลขนั้นจะไม่ถูกค้นด้วย
เลขตำแหน่งจะใช้เลขติดลบเพื่อคิดลำดับไล่จากท้ายมาก็ได้
alert(pk.indexOf("ฮาเน็กโกะ", 3)); // ได้ 4
alert(pk.indexOf("โปโปกโกะ", 2)); // ได้ 3
alert(pk.indexOf("วาตักโกะ", 3)); // ได้ -1
alert(pk.indexOf("วาตักโกะ", 2)); // ได้ 2
alert(pk.indexOf("โปโปกโกะ", -1)); // ได้ -1
alert(pk.indexOf("โปโปกโกะ", -2)); // ได้ 3
ฟังก์ชัน Array.isArray
ในออบเจ็กต์คอนสตรักเตอร์ Array มีฟังก์ชัน isArray
เอาไว้ใช้ตรวจสอบว่าข้อมูลตัวไหนเป็นแถวลำดับหรือเปล่า
ผลที่ได้จะคล้ายกับการใช้ instanceof array
แต่มีความแตกต่างกันเล็กน้อยในบางสถานการณ์
แต่เป็นรายละเอียดปลีกย่อยซึ่งจะยังไม่เขียนถึงตรงนี้
ตัวอย่าง
alert(Array.isArray([])); // ได้ true
alert(Array.isArray(new Array("ก", "ข", "ค", "ง"))); // ได้ true
alert(Array.isArray(Array.prototype)); // ได้ true
alert(Array.isArray("Array")); // ได้ false
alert(Array.isArray()); // ได้ false
alert(Array.isArray({})); // ได้ false
alert(Array.isArray(null)); // ได้ false
alert(Array.isArray(99)); // ได้ false
alert(Array.isArray(true)); // ได้ false
เนื้อหาในส่วนของ ES5 ก็จบลงเพียงเท่านี้
บทต่อจากนี้ไปจะเป็นพวกความสามารถเพิ่มเติมต่างๆใน ES6