ECMAScript3 ตอนที่ 3

ไม่ได้เขียนนานเนื่องจากความขี้เกียจ - -” เลยทิ้งมันไว้ซะนานขนาดนี้ วันนี้ก็เป็นโอกาสดีที่ว่าง ก็เลยทำต่อซะหน่อยก่อนจะขี้เกียจอีก ฮะๆๆ (วันนี้อาจเขียนอะไรเมินๆ แต่ถ้ามีเวลามากกว่านี้จะมานั่งเกลาภาษาอีกที ><")

Primitive และ Reference Values

ใน ECMAScript ตัวแปรสามารถเก็บข้อมูลได้สองแบบคือแบบ Primitive กับ Reverence

  • Primitive คือ ข้อมูลพื้นฐานต่างๆ ได้แก่ Undefined, Null, Boolean, String และ Numberโดยจะเก็บอยู่ใน Stack และสามารถเข้าถึงผ่านชื่อตัวแปรได้โดยตรง
  • Reference คือ ข้อมูลที่ถูกเก็บไว้ใน Heap โดยตัวแปรจะเก็บเพียงแค่ตำแหน่งของวัตถุก้อนนั้นเท่านั้น

เมื่อมีการกำหนดค่าให้กับตัวแปร ตัวแปลง ECMAScript ก็จะเอาค่ามาดูว่าเป็นประเภทใดระหว่าง Primitive หรือ Reference ถ้าเป็น Primitive ก็จะเอาไปเก็บไว้ใน Stack ที่ทำอย่างนี้เพราะว่าตัวแปรแบบ Primitive จะมีขนาดที่คงที่ ทำให้รู้ได้ว่าจะใช้พื้นที่เท่าไหร่ใน Stack เมื่อคำนวนแล้วนำไปเก็บใน Stack แล้วจะสามารถหาตำแหน่งได้อย่างเร็ว
สำหรับตัวแปรที่เป็น Reference ตำแหน่งจะเก็บอยู่ใน Stack แต่ข้อมูลจะเก็บอยู่ใน Heap เพื่อไม่ให้เวลาในการหาตัวแปรใน Stack นั้นลดลง

Primitive type

ใน ECMA-262 กำหนดไว้ว่า Type คือ ชุดของข้อมูล และ Primitive type แต่ละอย่างก็จะมีการระบุขนาดของข้อมูลและประเภทของมันด้วยว่าตัวแปรตัวนี้คืออะไร โดยหากต้องการดูก็สามารถดูได้ผ่าน คำสั่ง typeof

Type of

Type of ต้องการ parameter เพียงตัวเดียวคือ ตัวแปร หรือ ค่าที่ต้องการตรวจสอบเช่น


var sTemp = "test String"
alert(typeof sTemp) //outputs "string"
alert(typeof 95) //outputs "number"

สำหรับผลที่ได้เมื่อลองกับตัวแปรประเภทต่างๆ คือ

  • “undefined” สำหรับตัวแปรประเภทที่ยังไม่เคยกำหนดค่ามาก่อน(Undefined)
  • “boolean” สำหรับตัวแปรประเภท ถูก หรือ ผิด(boolean)
  • “number” สำหรับตัวแปรประเภทที่เป็นตัวเลข
  • “string” สำหรับตัวแปรที่เป็นสายอักขระ
  • “object” สำหรับตัวแปรประเภท null หรือ reference object

สำหรับ null ที่ให้ผลออกมาเป็น object เพราะการ implement ในจาวาสคริปส์รุ่นก่อน ซึ่งถือว่าเป็นที่ว่างเตรียมไว้สำหรับ object แต่ในทางเทคนิคแล้ว null ถือว่าเป็น primitive type อย่างหนึ่ง

Undefined

ตัวแปรประเภท Undefined คือตัวแปรที่ไม่เคยกำหนดค่ามาก่อนอย่างที่เขียนไปแล้วใน Type of เช่น

var oTemp

ตัวแปร oTemp ถูกประกาศขึ้นมาลอยๆ โดยที่ยังไม่มีการกำหนดค่าใดๆ ลงไปให้ เมื่อลองเปรียบเทียบตัวแปรนี้กับคำว่า undefined ผลที่ได้คือจริงเสมอ เช่น


var oTemp
alert(oTemp == undefined)

นอกจากตัวแปรที่ไม่ได้กำหนดค่าแล้ว ตัวแปรที่ยังไม่เคยประกาศมาก่อนหากลองทดสอบดูก็จะได้ค่าเป็น undefined ด้วยเช่นกัน เช่น


var oTemp

alert(oTemp) //output: undefined
alert(oTemp2) //output: undefined

แต่จะไม่สามารถเอาตัวแปรที่ยังไม่เคยประกาศใช้กับคำสั่งอื่นได้ เช่น


alert(oTemp2 == undefined) //causes error

นอกจากนี้ยังสามารถใช้ตรวจสอบกับ ฟังก์ชั่น ที่ไม่ให้ผลลัพธ์กลับมาได้ด้วยเช่น


function testFunc() {
}

alert(testFunct() == undefined) //outputs "true"

Null

Null และ Undefined นั้นมีลักษณะเหมือนกันเพราะ Undefined ถือว่าเป็น Null อย่างหนึ่งโดยหากเปรียบเทียบกันแล้วจะได้ค่าเป็นจริงออกมา


alert(null == undefined) //outputs "true"

แต่ทั้งสองค่านั้นเกิดต่างกัน undefined จะเกิดกับตัวแปรที่ยังไม่ได้กำหนดค่า แต่ null จะเกิดเมื่อตัวแปรนั้นเป็น object และไม่มีอยู่จริงแล้ว (เมื่อใช้ typeof กับ null จึงให้ค่ากลับมาเป็น object) เช่น ฟังก์ชั่นที่ต้องคืนวัตถุออกมาเป็น object ออกมาแต่ไม่คืนอะไรออกมาเลย เมื่อทดสอบแล้วจะได้ค่าออกมาเป็น null ไม่ไช่ undefined เหมือนตัวอย่างสุดท้ายของ undefined

Boolean

Boolean คือตัวแปรทางตรรกะพื้นฐานมีอยู่เพียงสองค่าเท่านั้นคือ จริง(true) กับ เท็จ(false) แต่ค่าเท็จนั้นจะไม่เท่ากับ 0 ยกเว้นถ้าเอา 0 มาใส่ให้ตัวแปรประเภทนี้จะถูกแปลงเป็นเท็จให้เพื่อความปลอดภัย


var bFound = true
var bLost = false

Number

Number ใน ECMAScript สามารถเป็นได้ทั้ง 32-bit Integer และ 64-bit Floatig point เช่น


var iNum = 55

และหากต้องการใส่เป็นเลขฐานแปดสามารถทำได้โดยกำหนดเลขหลักแรกเป็นศูนย์และเลขหลักถัดไปเป็นเลขในเลขฐานแปด (0-7) เช่น


var iNum = 070 //56 in decimal

และหากต้องการกำหนดเป็นเลขฐานสิบหกก็สามารถทำได้โดยการใส่ 0x นำหน้าตัวเลขฐานสิบหก เช่น


var iNum = 0x1f //31 in decimal
var iNum2 = 0xAB //171 in decimal

แม้ตัวเลขที่ใส่เข้าไปจะไม่ไช่เลขฐานสิบแต่ว่าเมื่อนำไปใช้คำนวนต่างๆ เลขเหล่านั้นจะถูกคำนวนในฐานสิบ
สำหรับการประกาศเลขแบบ Floating-point ก็ใส่ . แล้วตำแหน่งทศนิยมเข้าไปโดยตัวเลขเหล่านี้จะถูกเก็บเป็น String จนกว่าจะมีการนำไปใช้คำนวน เช่น


var fNum = 5.0

และหากเลขทศนิยมมีหลักมาก สามารถใช้สัญลักษณ์ e หรือ E เพื่อบอกจำนวนทศนิยมได้ โดยเลขหลัง e คือจำนวนเท่าของสิบ เช่น


var fNum = 3.125e7 //3.125x107
var fNum2 = 3.125e-7 //3.125x10-7

*ตัวเลขทศนิยมใน ECMAScript3 จะถูกเก็บแบบ 64-bit IEEE 754 โดยสามารถเก็บเลขได้ยาว 17 หลัก หากยาวกว่านั้นจะถูกตัด ทำให้อาจเกิดข้อผิดพลาดในตัวเลขที่มีขนาดน้อยมากๆ ได้
ตัวแปรประเภท Number ยังมีค่าพิเศษต่างๆ อีกเล็กน้อย สองตัวแรกคือ Number.MAX_VALUE และ Number.MIN_VALUE ตัวเลขที่ได้จากการคำนวนต่างๆ ต้องอยู่ภายในขอบเขตของค่าสองค่านี้เท่านั้นเพื่อนำไปคำนวนต่อได้ หาก ตัวเลขที่คำนวนออกมามีค่ามากกว่า Number.MAX_VALUE ผลลัพธ์ที่ได้คือ Number.POSITIVE_INFINITY ตรงกันข้ามหากน้อยกว่า Number.MIN_VALUE ก็จะได้เป็น Number.NEGATIVE_INFINITY ออกมา โดยตัวเลขเหล่านี้จะไม่สามารถนำไปคำนวนต่อได้อีก
เนื่องจากตัวเลขใน ECMAScript มีขอบเขตจึงมีการกำหนดฟังก์ชั่นขึ้นมาอีกอย่างคือ isFinite() เพื่อตรวจดูว่าตัวเลขเกินขอบเขตหรือยังเช่น


var iResult = iNum * some_really_large_number
if (isFinite(iResult)) {
  alert("Number is finite.")
} else {
  alert("Number is infinite.")
}

นอกจากนี้ยังมีค่าพิเศษอีกค่า นั่นคือ NaN โดยเป็นตัวย่อมาจากคำว่า “Not a Number” ซึ่งเกิดจากเมื่อมีการแปลงค่าจากตัวแปรอื่นมาเป็น Number แล้วล้มเหลวเช่น แปลงคำว่า “blue” มาเป็นตัวเลข และค่านี้เหมือนค่า infinity คือไม่สามารถนำมาใช้คำนวนได้ และตัวมันไม่เท่ากับตัวมันเองด้วย เช่น


alert(NaN == NaN) //outputs false

ดังนั้นหากจะตรวจสอบว่าเป็นค่า NaN หรือไม่ควรใช้ฟังก์ชั่น isNaN() ในการตรวจสอบเช่น


alert(isNaN("blue")) // outputs true
alert(isNaN("123")) // outputs false

String

String ถือว่าเป็น primitive type ตัวเดียวที่แปลกกว่าคนอื่นคือมีขนาดไม่แน่นอน โดยตัวอักษรในตัวแปรนี้จะเก็บแบบ 16-bit unicode และสามารถกำหนดให้ตัวแปรได้โดยใช้เครื่องหมาย ” หรือ ‘ ซึ่งในจาวาการกำหนด String จะใช้ ” ส่วน ‘ จะใช้สำหรับกำหนดประเภท Character แต่ ECMAScript ไม่มี Character ดังนั้นทั้งสองอย่างจึงใช้กำหนด String เหมือนกันเช่น


var sColor1 = "blue"
var sColor2 = 'red'

และยังมีตัวอักษรพิเศษอื่นๆ อีกเหมือนในภาษา Java,C หรือ perl คือ

  • \n ใช้สำหรับขึ้นบรรทัดใหม่
  • \t ใช้สำหรับ tab
  • \b ใช้สำหรับ backspace
  • \r ขึ้นบรรทัดใหม่แต่ไม่เลื่อนไปต้นบรรทัด
  • \f เลื่อนไปต้นบรรทัด(นึกถึงเครื่องพิมพ์ดีดไว้)
  • \\ เครื่องหมาย \
  • \’ เครื่องหมาย ‘
  • \” เครื่องหมาย “
  • \0nnn ตัวอักษรรหัส nnn เป็นเลขฐานแปด
  • \xnn ตัวอักษรรหัส nn เป็นเลขฐานสิบหก
  • \unnnn ตัวอักษรรหัส unicode ใช้เลขฐานสิบหก

การแปลงค่า

ลักษณะอย่างหนึ่งที่สำคัญสำหรับภาษาโปรแกรมต่างๆ คือการแปลงค่าระหว่างตัวแปรต่างๆ โดย ECMAScript ก็มีฟังก์ชั่นต่างๆ ให้เรียกใช้เพื่อแปลงตัวแปรต่างๆ คือ

การแปลงค่าเป็น String

สิ่งที่น่าสนใจอย่างหนึ่งในตัวแปรประเภท primitive คือมันเป็นเหมือน object เทียม ดังนั้นมันจึงมี property และฟังก์ชั่นต่างๆ เหมือน object เช่น


var sColor = "blue"
alert(sColor.length) //outputs 4

แม้ตัวแปร sColor จะเป็น String ซึ่งเป็น primitive type แต่ก็มี property เหมือน object คือ length โดยสามารถเอาค่าออกมาได้คือ 4 ซึ่งก็คือจำนวนตัวอักษรที่เก็บอยู่ใน String นี้นั่นเอง และนอกจากนี้ ทุก primitive type จะมีฟังก์ชั่นพื้นฐานอย่างนึงเหมือนกันหมดนั่นคือ toString() เพื่อใช้แปลงค่าเหล่านั้นเป็นประเภท String นั่นเอง
*อาจจะดูแปลกที่ String เองก็มีฟังก์ชั่น toString แต่ ECMAScript กำหนดไว้ว่า object ทุกอย่างแม้แต่ object เทียมต้องมีฟังก์ชั่น toString() เหมือนกันหมด คล้ายกับภาษาจาวา สำหรับใน Actionscript ก็มีเหมือนกัน สำหรับรายละเอียดแล้วจะเล่าอีกที แต่มีผลพอสมควรเมื่อใช้กับ Dictionary ใน Actionscript
การแปลง Boolean เป็น String จะได้ค่าออกมาสองอย่างคือ “true” หรือ “false” ตามแต่ค่าในตัวแปรขณะนั้น สำหรับ Number นั้นมีการแปลงอยู่สองแบบคือทั่วไป และ ใช้ฐานกำหนด โดยการแปลงแบบทั่วไปก็จะเปลี่ยนจาก ตัวเลขเป็น String ตามที่กำหนดใส่ตัวแปรเช่น


var iNum = 10
var fNum = 10.0
alert(iNum.toString()) //outputs "10"
alert(fNum.toString()) //outputs "10"

ตัวเลขทั้งหมดเมื่อใช้ toString() แล้วจะถูกแปลงเป็นเลขฐานสิบทั้งหมดไม่ว่าเมื่อตอนกำหนดค่าจะกำหนดด้วยฐานไหนก็ตาม แต่หากมีการกำหนดฐานเข้าไป String ที่ได้ก็จะถูกแปลงเป็นเลขฐานนั้นแต่ไม่มีสัญลักษณ์นำหน้าเหมือนตอนใส่เข้าไป เช่น


var iNum = 10
alert(iNum.toString(2)) //outputs "1010"
alert(iNum.toString(8)) //outputs "12"
alert(iNum.toString(16)) //output "A"

การแปลงค่าเป็นตัวเลข

ECMAScript กำหนดฟังก์ชั่นมาสองอย่างสำหรับแปลงค่าเป็นตัวเลขคือ parseInt() และ parseFloat() โดยจะสามารถใช้ได้กับตัวแปรที่เป็น String เท่านั้นหากใช้กับตัวแปรประเภทอื่นค่าที่ได้ออกมาคือ NaN เสมอ
parseInt() ทำงานโดยจะไล่ทดสอบตัวอักษรทีละตัวใน String ว่าเป็นตัวเลขหรือไม่เมื่อเป็นก็แปลงแล้วเก็บไว้แล้วไปตัวถัดไป ทำอย่างนี้ไปเรื่อยๆ จนกว่าจะเจอตัวอักษรที่ไม่ไช่ตัวเลข ดังนั้นหาก String มีค่าเท่ากับ “1234blue” เมื่อใช้ parseInt() แปลงค่าเป็นตัวเลข สิ่งที่ได้คือเลข 1234 นอกจากนี้ยังสามารถแปลง String ที่อยู่ในรูปฐานต่างๆ ได้อีกด้วยเช่น “0xA” เมื่อใช้ parseInt() จะได้ค่าออกมาเป็น 10 แต่หากใช้กับทศนิยม parseInt จะไปหยุดอยู่ที่ . ดังนั้นหาก String มีค่าเป็น “22.5″ เมื่อใช้ parseInt() แปลงออกมาจะได้แค่ 22 เช่น


var iNum1 = parseInt("1234blue") //returns 1234
var iNum2 = parseInt("0xA") //returns 10
var iNum3 = parseInt("22.5") //returns 22
var iNum4 = parseInt("blue") //returns NaN

parseInt() ยังสามารถแปลงโดยการกำหนดฐานให้กับฟังก์ชั่นได้ เช่นหากต้องการแปลง String เป็นเลขฐานสองก็จะกำหนดไปใน parameter ตัวที่สองว่า 2


var iNum1 = parseInt("AF", 16 ) //returns 175
var iNum2 = parseInt("10", 2 ) //returns 2
var iNum3 = parseInt("10", 8 ) //returns 8
var iNum4 = parseInt("10", 10 ) //returns 10

ถ้า String มีเลข 0 นำหน้าเมื่อแปลงค่าเลขที่ได้จะเหมือนแปลงจากเลขฐานแปด ดังนั้นควรกำหนดฐานด้วยทุกครั้งเช่น


var iNum1 = parseInt("010") //returns 8
var iNum2 = parseInt("010", 8 ) //returns 8
var iNum3 = parseInt("010", 10 ) //returns 10

สำหรับ parseFloat() ก็ทำงานคล้ายกับ parseInt() เพียงแต่เมื่อเจอ . ครั้งแรก parseFloat() จะไม่หยุดแต่จะทำงานต่อไปเรื่อยๆ จนกว่าจะเจอตัวอักษรหรือสัญลักษณ์ที่ไม่ไช่ตัวเลขครั้งที่สองเท่านั้น และ parseFloat() จะแปลงเลขฐานแปดต่างจาก parseInt() คือ parseFloat() จะไม่สนใจเลข 0 ตัวแรกเหมือน parseInt() ดังนั้นหากใช้ parseFloat() แปลงเลข 010 ค่าที่ได้ออกมาจะเท่ากับ 10 อีกอย่างคือ parseFloat() ไม่สามารถแปลงเลขฐานต่างๆ เหมือน parseInt() ได้อีกด้วยเช่น “0xA” parseFloat() จะให้ผลลัพธ์ออกมาเป็น NaN
ตัวอย่างการใช้ parseFloat()


var fNum1 = parseFloat("1234blue") //returns 1234.0
var fNum2 = parseFloat("0xA") //returns NaN
var fNum3 = parseFloat("22.5") //returns 22.5
var fNum4 = parseFloat("22.34.5") //returns 22.34
var fNum5 = parseFloat("0908") //returns 908
var fNum6 = parseFloat("blue") //returns NaN

การแปลงประเภทตัวแปร

การแปลงประเภทตัวแปรใน ECMAScript สามารถทำได้สามอย่างคือ

  • Boolean(value)
  • Number(value)
  • String(value)

การแปลงเป็น Boolean จะให้ค่าออกมาเป็น true เมื่อตัวแปรที่เป็น String มีตัวอักษรอย่างน้อย 1 ตัว, ตัวเลขที่ไม่ไช่ 0 หรือ วัตถุ และจะเป็น false เมื่อเป็น String ว่าง, เลข 0, undefined และ null เช่น


var b1 = Boolean("") //false
var b2 = Boolean("hi") //true
var b3 = Boolean(100) //true
var b4 = Boolean(null) //false
var b5 = Boolean(0) //false
var b6 = Boolean(new Object()) //true

์การแปลงเป็นตัวเลขโดยใช้ Number() คล้ายกับ parseInt และ parseFloat เพียงแต่จะไม่ได้สนใจทีละส่วนแต่จะดูทั้งหมดดังนั้น หาก String มีค่าเป็น “4.5.6″ จะไม่ได้ตัวเลขออกมาเป็น 4.5 แต่จะได้ค่าเป็น NaN แทน โดยผลลัพธ์จากการแปลงค่าตัวแปรประเภทต่างๆ ดูได้จากตาราง

  • Number(false) : 0
  • Number(true) : 1
  • Number(undefined) : NaN
  • Number(null) : 0
  • Number(”5.5″) : 5.5
  • Number(”56″) : 56
  • Number(”5.6.7″) : NaN
  • Number(new Object()) : NaN
  • Number(100) : 100

การแปลงค่าเป็น String โดยใช้ String(value) นั้นเหมือนกับเรียก object.toString() ทั่วไป

เห้อยาว กว่าจะเขียนจบตาแทบปิด แต่ยังเหลืออีกหลายเรื่องนัก ไว้คราวหน้าละกัน T T” ราตรีสวัสดิ์



Comments

  1. ผ่านมา September 13th

    Comment Arrow

    อืม พอดี ผ่านมาเห็นเว็บ พอดี ทำไมไม่ลง Credit ให้กับเจ้าของหนังสือหน่อยครับ แปลมา น่าจะให้เกียรติเจ้าของหนังสือด้วยนะครับ


  2. llun September 13th

    Comment Arrow

    @ผ่านมา จริงๆ ผมลงไว้ตั้งแต่ตอนแรกแล้วหละ แต่ไม่ได้ทำเป็นลิงค์ให้เท่านั้นเอง ที่ http://llun.info/archives/317 ไว้ทำต่อแล้วเดี๊ยวใส่ไว้ทุกตอนละกัน


Add Yours

  • Author Avatar

    YOU


Comment Arrow



About Author

llun

Apple addict programmer