$scope ใน AngularJS คืออะไร? บทช่วยสอนพร้อมตัวอย่าง
⚡ สรุปอย่างชาญฉลาด
$Scope ใน AngularJS เป็นอ็อบเจ็กต์ในตัวที่ใช้เชื่อมโยงคอนโทรลเลอร์กับวิว หน้านี้จะอธิบายเกี่ยวกับการสร้างสโคป ฟังก์ชันการทำงาน ลำดับชั้นของพาเรนต์และลูก ความแตกต่างจาก $rootScope และวิธีการที่วงจรไดเจสต์รีเฟรชการเชื่อมโยง
$scope ใน AngularJS คืออะไร?
$ขอบเขตใน AngularJS เป็นวัตถุในตัวซึ่งโดยทั่วไปจะผูก "ตัวควบคุม" และ "มุมมอง" เราสามารถกำหนดตัวแปรสมาชิกในขอบเขตภายในตัวควบคุมซึ่งสามารถเข้าถึงได้โดยมุมมอง
ตัวควบคุมทุกตัวใน AngularJS แอปพลิเคชันจะได้รับอินสแตนซ์ `$scope` ของตัวเองผ่านการฉีดการพึ่งพา (dependency injection) สิ่งใดก็ตามที่คุณแนบเข้ากับอ็อบเจ็กต์นั้นจะสามารถมองเห็นได้ในเทมเพลตที่คอนโทรลเลอร์ควบคุม ดังนั้น `$scope` จึงทำหน้าที่เป็นโมเดลข้อมูลที่ใช้ร่วมกันซึ่งอยู่ระหว่างแอปพลิเคชันและคอนโทรลเลอร์ของคุณ Javaตรรกะของสคริปต์และโค้ด HTML ของคุณ
พิจารณาตัวอย่างด้านล่าง:
angular.module('app',[]).controller('HelloWorldCtrl', function($scope) { $scope.message = "Hello World" });
Code คำอธิบาย:
- ชื่อของโมดูลคือ "แอป"
- ชื่อของตัวควบคุมคือ “HelloWorldCtrl”
- วัตถุขอบเขตเป็นวัตถุหลักที่ใช้ในการส่งข้อมูลจากตัวควบคุมไปยังมุมมอง
- เพิ่มตัวแปรสมาชิกให้กับวัตถุขอบเขต
⚠️ คำเตือนเกี่ยวกับไวยากรณ์: การขอ .controller() เมธอดนี้รับอาร์กิวเมนต์สองตัว คือ ชื่อคอนโทรลเลอร์และฟังก์ชันโรงงาน ดังนั้นจึงต้องคั่นด้วยเครื่องหมายจุลภาค 'HelloWorldCtrl' และ function($scope)การไม่ใส่เครื่องหมายจุลภาคทำให้เกิดข้อผิดพลาด Uncaught SyntaxError ก่อนที่ AngularJS จะเริ่มทำงาน
ตัวควบคุมเพียงตัวเดียวและมุมมองเดียวเป็นเพียงครึ่งหนึ่งของภาพรวมทั้งหมด แอปพลิเคชันในความเป็นจริงมักมีการซ้อนตัวควบคุม ทำซ้ำรายการ และนำวิดเจ็ตกลับมาใช้ใหม่ ซึ่งหมายความว่ามีขอบเขตหลายอย่างเกิดขึ้นพร้อมกัน
ลำดับชั้นของขอบเขตและการสืบทอดทำงานอย่างไรใน AngularJS
แอปพลิเคชัน AngularJS ทุกแอปพลิเคชันจะมีขอบเขตหลัก (root scope) เพียงหนึ่งเดียว และอาจมีขอบเขตย่อย (child scope) ได้หลายขอบเขต ไดเร็กทีฟ (Directives) จะสร้างขอบเขตย่อยเหล่านั้นและแนบเข้ากับองค์ประกอบ DOM ที่มันตกแต่ง ดังนั้นโครงสร้างของขอบเขตจึงสะท้อนโครงสร้างของหน้าเว็บที่แสดงผล
เมื่อ AngularJS ประเมินนิพจน์ เช่น {{siteName}}โดยจะค้นหาคุณสมบัตินั้นในขอบเขตที่แนบมากับองค์ประกอบก่อน หากไม่พบคุณสมบัตินั้น การค้นหาจะย้ายไปยังขอบเขตแม่ และจะค้นหาต่อไปเรื่อยๆ จนกว่าจะถึงขอบเขตราก Javaนักพัฒนาสคริปต์รู้จักพฤติกรรมนี้ในชื่อการสืบทอดแบบโปรโตไทป์ และขอบเขตย่อยจะสืบทอดจากขอบเขตแม่ในลักษณะนั้นอย่างแน่นอน
ตัวอย่างด้านล่างนี้แสดงการซ้อนคอนโทรลเลอร์หนึ่งไว้ภายในอีกคอนโทรลเลอร์หนึ่ง เพื่อให้คุณสามารถสังเกตการสืบทอดคุณสมบัติได้
<div ng-app="scopeDemo"> <div ng-controller="ParentCtrl"> Parent scope value: {{siteName}} <div ng-controller="ChildCtrl"> Child reads parent value: {{siteName}} Child own value: {{lesson}} </div> </div> </div> <script type="text/javascript"> var app = angular.module("scopeDemo", []); app.controller("ParentCtrl", function($scope) { $scope.siteName = "Guru99"; }); app.controller("ChildCtrl", function($scope) { $scope.lesson = "AngularJS Scope"; }); </script>
Code คำอธิบาย:
ParentCtrlกำหนดsiteNameในขอบเขตของมันเองChildCtrlไม่เคยกำหนดsiteNameแต่ div ด้านในยังคงแสดงผลอยู่ Guru99 เนื่องจากการค้นหาจะไปยังขอบเขตหลักlessonตัวแปรนี้มีอยู่เฉพาะในขอบเขตของ div ย่อยเท่านั้น ดังนั้น div แม่จึงไม่สามารถอ่านได้
คำสั่งใดบ้างที่สร้างขอบเขตใหม่?
- ng-controller: สร้างขอบเขตย่อยสำหรับองค์ประกอบที่วางไว้
- ng-repeat: สร้างขอบเขตย่อยหนึ่งรายการต่อการวนซ้ำ ซึ่งเป็นเหตุผลว่าทำไมแต่ละแถวจึงสามารถเก็บค่าที่แตกต่างกันสำหรับนิพจน์เดียวกันได้
- คำสั่งที่กำหนดเอง: อาจขอตรวจดูเด็ก หรือ แยก ขอบเขตที่ไม่สืบทอดคุณสมบัติจากขอบเขตแม่โดยเจตนา
- คำสั่งของส่วนประกอบ: สิ่งใดก็ตามที่ลงทะเบียนไว้กับ
.component()ตัวช่วยจะได้รับขอบเขตแบบแยกเดี่ยวเสมอ
เนื่องจากขอบเขตของลูกจะอ่านค่าจากล่างขึ้นบน นักพัฒนาจึงมักสงสัยว่าจุดสูงสุดของลำดับนั้นอยู่ที่ใด วัตถุระดับบนสุดนั้นเรียกว่า $rootScope
$scope กับ $rootScope ต่างกันอย่างไร?
แองกูลาร์เจเอส $rootScope $rootScope คือขอบเขตสำหรับแอปพลิเคชันทั้งหมด แอปพลิเคชันหนึ่งๆ จะมี $rootScope ได้เพียงหนึ่งเดียวเท่านั้น และมันถูกใช้งานเหมือนตัวแปรส่วนกลาง $scope ทุกตัวเป็นขอบเขตย่อย และ $rootScope เป็นขอบเขตหลักที่อยู่บนสุดของโครงสร้าง ตารางด้านล่างเปรียบเทียบวัตถุทั้งสองนี้
| แง่มุม | $ขอบเขต | $rootScope |
|---|---|---|
| อินสแตนซ์ต่อแอปพลิเคชัน | หลายตัว โดยแต่ละตัวจะอยู่บนตัวควบคุมหรือคำสั่งสร้างขอบเขตหนึ่งตัว | หนึ่งอันพอดี |
| จัดทำโดย | คำสั่งเช่น ng-controller และ ng-repeat | ตัวฉีดระหว่างการบูตแอปพลิเคชัน |
| แพ็กเกจ | องค์ประกอบของมันเองและลูกหลานทั้งหมด | ทุกขอบเขตในแอปพลิเคชัน |
| การใช้งานทั่วไป | ข้อมูลและพฤติกรรมสำหรับมุมมองเดียวหรือแถวรายการเดียว | ค่าต่างๆ ที่แสดงผลทั่วทั้งแอปพลิเคชัน เช่น ผู้ใช้ที่เข้าสู่ระบบ |
| ความเสี่ยงหลัก | คุณค่าต่างๆ จะไม่สามารถเข้าถึงได้หากอยู่นอกสาขานี้ | การชนกันของชื่อและการเชื่อมโยงที่ซ่อนเร้น เช่น ตัวแปรส่วนกลาง |
ควรใช้ $rootScope อย่างระมัดระวัง สิ่งใดก็ตามที่จัดเก็บไว้ในนั้นจะคงอยู่ตลอดทั้งแอปพลิเคชันและสามารถอ่านได้ทุกที่ ดังนั้นโดยทั่วไปแล้วบริการที่ใช้ร่วมกันจึงเป็นสถานที่ที่ปลอดภัยกว่าสำหรับสถานะส่วนกลาง (อย่างเป็นทางการ) การอ้างอิง $rootScope แสดงรายการ API ทั้งหมด
การรู้ว่าข้อมูลอยู่ที่ไหนเป็นเพียงครึ่งหนึ่งของงาน อีกครึ่งหนึ่งคือการสอนให้ระบบตอบสนองอย่างไรเมื่อผู้ใช้ทำบางสิ่งบางอย่าง
การตั้งค่าหรือเพิ่มพฤติกรรมใน AngularJS
เพื่อที่จะตอบสนองต่อเหตุการณ์หรือดำเนินการคำนวณ/ประมวลผลบางประเภทในมุมมอง เราต้องจัดให้มีพฤติกรรมในขอบเขต
พฤติกรรมจะถูกเพิ่มให้กับวัตถุขอบเขตเพื่อตอบสนองต่อเหตุการณ์เฉพาะที่อาจถูกกระตุ้นโดยมุมมอง เมื่อกำหนดพฤติกรรมในคอนโทรลเลอร์แล้ว มุมมองจะสามารถเข้าถึงได้
ลองดูตัวอย่างว่าเราจะบรรลุเป้าหมายนี้ได้อย่างไร
<!DOCTYPE html> <html lang="en"> <head> <meta chrset="UTF 8"> <title>Guru99</title> </head> <body ng-app="DemoApp"> <h1> Guru99 Global Event</h1> <script src="https://code.angularjs.org/1.6.9/angular.js"></script> <div ng-controller="DemoController"> {{fullName("Guru","99")}} </div> <script type="text/javascript"> var app = angular.module("DemoApp", []); app.controller("DemoController", function($scope) { $scope.fullName=function(firstName,lastname){ return firstName + lastname; } } ); </script> </body> </html>
Code คำอธิบาย:
- เรากำลังสร้างพฤติกรรมที่เรียกว่า "ชื่อเต็ม" ลักษณะการทำงานนี้เป็นฟังก์ชันที่ยอมรับ 2 พารามิเตอร์ (ชื่อ, นามสกุล)
- ลักษณะการทำงานจะส่งกลับการต่อกันของพารามิเตอร์ 2 ตัวนี้
- ในมุมมองนี้ เรากำลังเรียกใช้พฤติกรรมและส่งค่า 2 ค่าของ “Guru“และ “99” ซึ่งจะถูกส่งผ่านเป็นพารามิเตอร์ไปยังพฤติกรรม
หากดำเนินการคำสั่งสำเร็จ ผลลัพธ์ต่อไปนี้จะปรากฏขึ้นเมื่อคุณรันโค้ดในเบราว์เซอร์
Output:
ในเบราว์เซอร์ คุณจะเห็นการรวมกันของค่าทั้งสอง Guru และ 99 ซึ่งถูกส่งต่อไปยังพฤติกรรมใน ตัวควบคุม.
การเชื่อมโยงข้อมูลแบบที่แสดงด้านบนจะรีเฟรชตัวเองโดยอัตโนมัติ และกลไกที่ทำให้เกิดสิ่งนั้นเป็นสิ่งสำคัญที่ควรทำความเข้าใจก่อนที่แอปพลิเคชันจะเติบโตจนมีขนาดใหญ่
เหตุใด Scope Watchers และ Digest Cycle จึงมีความสำคัญ
AngularJS รักษาความสอดคล้องของมุมมองกับขอบเขตโดยใช้การตรวจสอบการเปลี่ยนแปลง (dirty checking) แทนที่จะใช้เหตุการณ์การเปลี่ยนแปลง (change events) โดยมี API สามตัวที่ขับเคลื่อนกระบวนการนี้:
- $watch: ลงทะเบียนผู้ฟังสำหรับนิพจน์ การแทรกค่า เช่น
{{fullName}}ลงทะเบียนผู้ติดตามให้คุณระหว่างการเชื่อมโยงเทมเพลต - $apply: ฟังก์ชันนี้จะเข้าสู่บริบทการทำงานของ AngularJS ประเมินโค้ดของคุณ แล้วจึงเรียกใช้ฟังก์ชัน digest จำเป็นต้องใช้เฉพาะภายใน callback เหตุการณ์แบบกำหนดเองหรือ callback ของไลบรารีภายนอกเท่านั้น เนื่องจาก directive ที่มีอยู่แล้วได้เรียกใช้ฟังก์ชันนี้อยู่แล้ว
- $digest: วนลูปผ่านตัวเฝ้าดูทุกตัวบน $rootScope และลูกๆ ของมัน เปรียบเทียบค่าปัจจุบันกับค่าก่อนหน้า และทำซ้ำจนกว่าโมเดลจะหยุดเปลี่ยนแปลง
เนื่องจากกระบวนการไดเจสต์สามารถทำงานได้หลายรอบ ดังนั้นนิพจน์การตรวจสอบจึงต้องมีต้นทุนต่ำ หลีกเลี่ยงการเข้าถึง DOM ภายในนิพจน์เหล่านั้น เนื่องจาก1การอ่าน DOM นั้นช้ากว่าการอ่านนิพจน์การตรวจสอบหลายเท่า Javaคุณสมบัติของสคริปต์
ความลึกของการเฝ้าสังเกตก็ส่งผลต่อต้นทุนเช่นกัน การเฝ้าสังเกตโดยใช้ข้อมูลอ้างอิงเป็นวิธีที่เร็วที่สุด และจะสังเกตเห็นได้ก็ต่อเมื่อค่าทั้งหมดถูกแทนที่แล้วเท่านั้น $watchCollection ฟังก์ชันนี้จะแจ้งเตือนเมื่อมีการเพิ่ม ลบ หรือจัดเรียงลำดับรายการใหม่ภายในอาร์เรย์หรืออ็อบเจ็กต์ การตรวจสอบด้วยค่าจะวนลูปผ่านโครงสร้างแบบซ้อนกันในทุกๆ การตรวจสอบ และเป็นตัวเลือกที่แพงที่สุด ดังนั้นควรเลือกใช้เป็นตัวเลือกสุดท้าย




