ในการเขียนโปรแกรมเชิงวัตถุ คลาส คือเทมเพลตรหัสโปรแกรมที่ขยายได้สำหรับการสร้างอ็อบเจ็กต์ โดยให้ค่าเริ่มต้นสำหรับสถานะ (ตัวแปรสมาชิก) และการประยุกต์ใช้พฤติกรรม (ฟังก์ชันหรือเมธอดของสมาชิก)
ในทางปฏิบัติ เรามักจะจำเป็นต้องสร้างวัตถุประเภทเดียวกันหลายอย่าง เช่น ผู้ใช้ สินค้า หรืออะไรก็ตาม
ดังที่เราทราบแล้วจากบท Constructor ตัวดำเนินการ "ใหม่" new function
สามารถช่วยได้
แต่ใน JavaScript สมัยใหม่ มีโครงสร้าง "คลาส" ขั้นสูงกว่าที่แนะนำคุณสมบัติใหม่ที่ยอดเยี่ยมซึ่งมีประโยชน์สำหรับการเขียนโปรแกรมเชิงวัตถุ
ไวยากรณ์พื้นฐานคือ:
คลาส MyClass { // วิธีการเรียน ตัวสร้าง () { ... } วิธีที่ 1() { ... } method2() { ... } method3() { ... } - -
จากนั้นใช้ new MyClass()
เพื่อสร้างวัตถุใหม่ด้วยวิธีการที่ระบุไว้ทั้งหมด
เมธอด constructor()
ถูกเรียกโดยอัตโนมัติด้วย new
ดังนั้นเราจึงสามารถเริ่มต้นอ็อบเจ็กต์ที่นั่นได้
ตัวอย่างเช่น:
ผู้ใช้คลาส { ตัวสร้าง (ชื่อ) { this.name = ชื่อ; - พูดสวัสดี() { การแจ้งเตือน (this.name); - - // การใช้งาน: ให้ผู้ใช้ = ผู้ใช้ใหม่ ("จอห์น"); user.sayHi();
เมื่อ new User("John")
ถูกเรียก:
มีการสร้างวัตถุใหม่
constructor
ทำงานพร้อมกับอาร์กิวเมนต์ที่กำหนดและกำหนดให้กับ this.name
…จากนั้นเราก็สามารถเรียกเมธอดอ็อบเจ็กต์ได้ เช่น user.sayHi()
ไม่มีลูกน้ำระหว่างวิธีการเรียน
ข้อผิดพลาดทั่วไปสำหรับนักพัฒนามือใหม่คือการใส่ลูกน้ำระหว่างวิธีการเรียน ซึ่งจะส่งผลให้เกิดข้อผิดพลาดทางไวยากรณ์
สัญกรณ์ในที่นี้อย่าสับสนกับอ็อบเจกต์ตัวอักษร ภายในชั้นเรียนไม่จำเป็นต้องใช้ลูกน้ำ
แล้วจริงๆ แล้ว class
คืออะไรล่ะ? นั่นไม่ใช่เอนทิตีระดับภาษาใหม่ทั้งหมดอย่างที่เราคิด
มาเปิดเผยเวทมนตร์และดูว่าจริงๆ แล้วคลาสคืออะไร นั่นจะช่วยในการทำความเข้าใจแง่มุมที่ซับซ้อนหลายประการ
ใน JavaScript คลาสคือฟังก์ชันชนิดหนึ่ง
ที่นี่ลองดู:
ผู้ใช้คลาส { ตัวสร้าง (ชื่อ) { this.name = ชื่อ; - sayHi() { การแจ้งเตือน (this.name); - - // พิสูจน์: ผู้ใช้คือฟังก์ชัน การแจ้งเตือน (ประเภทของผู้ใช้); // การทำงาน
โครงสร้าง class User {...}
ใดที่ทำได้จริงคือ:
สร้างฟังก์ชันชื่อ User
ซึ่งกลายเป็นผลลัพธ์ของการประกาศคลาส รหัสฟังก์ชันนำมาจากวิธี constructor
(ถือว่าว่างเปล่าหากเราไม่เขียนวิธีการดังกล่าว)
จัดเก็บวิธีการเรียนเช่น sayHi
ใน User.prototype
หลังจากที่อ็อบเจ็กต์ new User
ถูกสร้างขึ้น เมื่อเราเรียกเมธอดของมัน มันก็จะนำมาจากต้นแบบ เช่นเดียวกับที่อธิบายไว้ในบท F.prototype ดังนั้นวัตถุจึงสามารถเข้าถึงวิธีการเรียนได้
เราสามารถแสดงผลลัพธ์ของการประกาศ class User
ได้ดังนี้:
นี่คือรหัสเพื่อวิปัสสนา:
ผู้ใช้คลาส { ตัวสร้าง (ชื่อ) { this.name = ชื่อ; - sayHi() { การแจ้งเตือน (this.name); - - // class คือฟังก์ชัน การแจ้งเตือน (ประเภทของผู้ใช้); // การทำงาน // ...หรือที่เจาะจงกว่านั้นคือวิธี Constructor การแจ้งเตือน (ผู้ใช้ === User.prototype.constructor); // จริง // วิธีการอยู่ใน User.prototype เช่น: การแจ้งเตือน (User.prototype.sayHi); // โค้ดของเมธอด sayHi // มีสองวิธีในต้นแบบ การแจ้งเตือน (Object.getOwnPropertyNames (User.prototype)); // Constructor พูดสวัสดี
บางครั้งผู้คนบอกว่า class
นั้นเป็น "น้ำตาลเชิงวากยสัมพันธ์" (ไวยากรณ์ที่ออกแบบมาเพื่อให้อ่านง่ายขึ้น แต่ไม่ได้แนะนำสิ่งใหม่) เพราะจริงๆ แล้วเราสามารถประกาศสิ่งเดียวกันได้โดยไม่ต้องใช้คีย์เวิร์ด class
เลย:
// เขียนคลาส User ใหม่ด้วยฟังก์ชันล้วนๆ // 1. สร้างฟังก์ชันคอนสตรัคเตอร์ ผู้ใช้ฟังก์ชัน (ชื่อ) { this.name = ชื่อ; - // ต้นแบบฟังก์ชันมีคุณสมบัติ "ตัวสร้าง" เป็นค่าเริ่มต้น // ดังนั้นเราจึงไม่จำเป็นต้องสร้างมันขึ้นมา // 2. เพิ่มวิธีการให้กับต้นแบบ User.prototype.sayHi = ฟังก์ชั่น () { การแจ้งเตือน (this.name); - // การใช้งาน: ให้ผู้ใช้ = ผู้ใช้ใหม่ ("จอห์น"); user.sayHi();
ผลลัพธ์ของคำจำกัดความนี้ก็ใกล้เคียงกัน ดังนั้นจึงมีเหตุผลว่าทำไม class
จึงถือเป็นน้ำตาลวากยสัมพันธ์เพื่อกำหนดตัวสร้างร่วมกับวิธีการต้นแบบ
ถึงกระนั้นก็มีความแตกต่างที่สำคัญ
ขั้นแรก ฟังก์ชันที่สร้างโดย class
จะมีป้ายกำกับโดยคุณสมบัติภายในพิเศษ [[IsClassConstructor]]: true
ดังนั้นจึงไม่เหมือนกับการสร้างด้วยตนเองโดยสิ้นเชิง
มีการตรวจสอบภาษาสำหรับคุณสมบัตินั้นในสถานที่ต่างๆ ตัวอย่างเช่น จะต้องเรียกใช้ด้วย new
: ซึ่งต่างจากฟังก์ชันทั่วไป
ผู้ใช้คลาส { ตัวสร้าง () {} - การแจ้งเตือน (ประเภทของผู้ใช้); // การทำงาน ผู้ใช้(); // ข้อผิดพลาด: ผู้ใช้ตัวสร้างคลาสไม่สามารถเรียกใช้ได้หากไม่มี 'ใหม่'
นอกจากนี้ การแสดงสตริงของตัวสร้างคลาสในเอ็นจิ้น JavaScript ส่วนใหญ่เริ่มต้นด้วย “คลาส…”
ผู้ใช้คลาส { ตัวสร้าง () {} - การแจ้งเตือน (ผู้ใช้); // ผู้ใช้คลาส { ... }
มีความแตกต่างอื่น ๆ เราจะเห็นพวกเขาเร็ว ๆ นี้
วิธีการเรียนไม่สามารถนับได้ คำจำกัดความของคลาสตั้งค่าแฟล็ก enumerable
false
สำหรับวิธีการทั้งหมดใน "prototype"
นั่นเป็นสิ่งที่ดี เพราะถ้าเรา for..in
เหนือ object เราก็มักจะไม่ต้องการวิธี class ของมัน
คลาส use strict
เสมอ รหัสทั้งหมดภายในโครงสร้างคลาสจะอยู่ในโหมดเข้มงวดโดยอัตโนมัติ
นอกจากนี้ ไวยากรณ์ class
ยังมีคุณลักษณะอื่นๆ อีกมากมายที่เราจะสำรวจในภายหลัง
เช่นเดียวกับฟังก์ชัน คลาสสามารถกำหนดไว้ในนิพจน์อื่น ส่งต่อ ส่งคืน มอบหมาย ฯลฯ
นี่คือตัวอย่างของการแสดงออกในชั้นเรียน:
ให้ผู้ใช้ = คลาส { พูดสวัสดี() { alert("สวัสดี"); - -
คล้ายกับ Named Function Expressions นิพจน์คลาสอาจมีชื่อ
หากนิพจน์คลาสมีชื่อ จะมองเห็นได้ภายในคลาสเท่านั้น:
// "นิพจน์คลาสที่มีชื่อ" // (ไม่มีคำดังกล่าวในข้อมูลจำเพาะ แต่คล้ายกับ Named Function Expression) ให้ผู้ใช้ = คลาส MyClass { พูดสวัสดี() { การแจ้งเตือน (MyClass); // ชื่อ MyClass จะปรากฏเฉพาะภายในชั้นเรียนเท่านั้น - - ผู้ใช้ใหม่().sayHi(); // ใช้งานได้ แสดงคำจำกัดความของ MyClass การแจ้งเตือน (MyClass); // ข้อผิดพลาด ชื่อ MyClass ไม่ปรากฏภายนอกชั้นเรียน
เรายังสามารถสร้างคลาสแบบ "ตามความต้องการ" แบบไดนามิกได้ เช่นนี้
ฟังก์ชั่น makeClass (วลี) { // ประกาศคลาสและส่งคืน กลับคลาส { พูดสวัสดี() { การแจ้งเตือน(วลี); - - - // สร้างคลาสใหม่ ให้ User = makeClass("Hello"); ผู้ใช้ใหม่().sayHi(); // สวัสดี
เช่นเดียวกับวัตถุตามตัวอักษร คลาสอาจรวมถึง getters/setters คุณสมบัติการคำนวณ ฯลฯ
นี่คือตัวอย่างสำหรับ user.name
ที่ใช้งานโดยใช้ get/set
:
ผู้ใช้คลาส { ตัวสร้าง (ชื่อ) { // เรียกตัวตั้งค่า this.name = ชื่อ; - รับชื่อ () { ส่งคืนสิ่งนี้._name; - ตั้งชื่อ (ค่า) { ถ้า (value.length < 4) { alert("ชื่อสั้นเกินไป"); กลับ; - this._name = ค่า; - - ให้ผู้ใช้ = ผู้ใช้ใหม่ ("จอห์น"); การแจ้งเตือน (ชื่อผู้ใช้); // จอห์น ผู้ใช้ = ผู้ใช้ใหม่ (""); // ชื่อสั้นเกินไป
ในทางเทคนิคแล้ว การประกาศคลาสดังกล่าวทำงานโดยการสร้าง getters และ setters ใน User.prototype
นี่คือตัวอย่างที่มีชื่อวิธีการคำนวณโดยใช้วงเล็บ [...]
:
ผู้ใช้คลาส { ['พูด' + 'สวัสดี']() { alert("สวัสดี"); - - ผู้ใช้ใหม่().sayHi();
คุณลักษณะดังกล่าวง่ายต่อการจดจำ เนื่องจากมีลักษณะคล้ายกับวัตถุตามตัวอักษร
เบราว์เซอร์รุ่นเก่าอาจต้องใช้โพลีฟิล
ช่องของชั้นเรียนเป็นส่วนเสริมล่าสุดของภาษา
ก่อนหน้านี้ชั้นเรียนของเรามีเพียงวิธีการเท่านั้น
“ฟิลด์คลาส” คือไวยากรณ์ที่อนุญาตให้เพิ่มคุณสมบัติใดๆ ได้
ตัวอย่างเช่น ลองเพิ่ม name
property ให้กับ class User
:
ผู้ใช้คลาส { ชื่อ = "จอห์น"; พูดสวัสดี() { alert(`สวัสดี ${this.name}!`); - - ผู้ใช้ใหม่().sayHi(); // สวัสดีจอห์น!
เราก็เลยเขียนว่า “
ความแตกต่างที่สำคัญของฟิลด์คลาสคือพวกมันถูกตั้งค่าบนอ็อบเจ็กต์แต่ละรายการ ไม่ใช่ User.prototype
:
ผู้ใช้คลาส { ชื่อ = "จอห์น"; - ให้ผู้ใช้ = ผู้ใช้ใหม่ (); การแจ้งเตือน (ชื่อผู้ใช้); // จอห์น การแจ้งเตือน (User.prototype.name); // ไม่ได้กำหนด
นอกจากนี้เรายังสามารถกำหนดค่าโดยใช้นิพจน์และการเรียกใช้ฟังก์ชันที่ซับซ้อนมากขึ้น:
ผู้ใช้คลาส { name = prompt("ขอชื่อหน่อยได้ไหม?", "จอห์น"); - ให้ผู้ใช้ = ผู้ใช้ใหม่ (); การแจ้งเตือน (ชื่อผู้ใช้); // จอห์น
ดังที่แสดงให้เห็นในบท Function Binding Functions ใน JavaScript มีไดนามิก this
ขึ้นอยู่กับบริบทของการโทร
ดังนั้นหากเมธอด object ถูกส่งผ่านไปและเรียกใช้ในบริบทอื่น this
จะไม่อ้างอิงถึงอ็อบเจ็กต์ของมันอีกต่อไป
ตัวอย่างเช่น รหัสนี้จะแสดง undefined
:
ปุ่มคลาส { ตัวสร้าง (ค่า) { this.value = ค่า; - คลิก() { การแจ้งเตือน (this.value); - - ให้ปุ่ม = ปุ่มใหม่ ("สวัสดี"); setTimeout(ปุ่ม.คลิก, 1,000); // ไม่ได้กำหนด
ปัญหานี้เรียกว่า "การสูญเสีย this
"
มีสองวิธีในการแก้ไข ดังที่กล่าวไว้ในบท Function Binding:
ส่งผ่านฟังก์ชัน wrapper เช่น setTimeout(() => button.click(), 1000)
ผูกวิธีการกับวัตถุ เช่นในตัวสร้าง
ฟิลด์คลาสมีไวยากรณ์ที่สวยงามอีกแบบหนึ่ง:
ปุ่มคลาส { ตัวสร้าง (ค่า) { this.value = ค่า; - คลิก = () => { การแจ้งเตือน (this.value); - - ให้ปุ่ม = ปุ่มใหม่ ("สวัสดี"); setTimeout(ปุ่ม.คลิก, 1,000); // สวัสดี
ฟิลด์คลาส click = () => {...}
ถูกสร้างขึ้นแบบต่ออ็อบเจ็กต์ มีฟังก์ชันแยกต่างหากสำหรับอ็อบเจ็กต์ Button
แต่ละรายการ โดย this
จะอ้างอิงถึงอ็อบเจ็กต์นั้น เราสามารถส่งผ่าน button.click
คลิกที่ใดก็ได้ และค่าของ this
จะถูกต้องเสมอ
ซึ่งมีประโยชน์อย่างยิ่งในสภาพแวดล้อมของเบราว์เซอร์ สำหรับผู้ฟังเหตุการณ์
ไวยากรณ์ของคลาสพื้นฐานมีลักษณะดังนี้:
คลาส MyClass { เสา = ค่า; // คุณสมบัติ ตัวสร้าง (...) { // ตัวสร้าง - - method(...) {} // method รับบางสิ่งบางอย่าง(...) {} // วิธีการรับ ตั้งค่าบางสิ่งบางอย่าง(...) {} // วิธีการตั้งค่า [Symbol.iterator]() {} // วิธีการที่มีชื่อที่คำนวณได้ (สัญลักษณ์ที่นี่) - -
MyClass
เป็นฟังก์ชันในทางเทคนิค (ฟังก์ชันที่เราจัดเตรียมไว้เป็น constructor
) ในขณะที่เมธอด getters และ setters จะถูกเขียนลงใน MyClass.prototype
ในบทต่อไป เราจะเรียนรู้เพิ่มเติมเกี่ยวกับคลาสต่างๆ รวมถึงการสืบทอดและคุณลักษณะอื่นๆ
ความสำคัญ: 5
คลาส Clock
(ดูแซนด์บ็อกซ์) เขียนในรูปแบบการใช้งาน เขียนใหม่ในรูปแบบ "คลาส"
ป.ล. นาฬิกาติ๊กในคอนโซลเปิดดู
เปิดแซนด์บ็อกซ์สำหรับงาน
นาฬิกาชั้นเรียน { ตัวสร้าง ({ เทมเพลต }) { this.template = เทมเพลต; - แสดงผล() { ให้วันที่ = วันที่ใหม่ (); ให้ชั่วโมง = date.getHours(); ถ้า (ชั่วโมง < 10) ชั่วโมง = '0' + ชั่วโมง; ให้ mins = date.getMinutes(); ถ้า (นาที < 10) นาที = '0' + นาที; ให้วินาที = date.getSeconds(); ถ้า (วินาที < 10) วินาที = '0' + วินาที; ให้เอาต์พุต = this.template .replace('h', ชั่วโมง) .replace('m', นาที) .replace('s', วินาที); console.log(เอาท์พุท); - หยุด() { clearInterval(this.timer); - เริ่ม() { นี้.render(); this.timer = setInterval(() => this.render(), 1,000); - - ให้นาฬิกา = นาฬิกาใหม่ ({template: 'h:m:s'}); นาฬิกา.เริ่มต้น();
เปิดโซลูชันในแซนด์บ็อกซ์