ما هو $scope في AngularJS؟ شرح مع مثال

⚡ ملخص ذكي

يُعدّ $Scope في AngularJS كائنًا مُدمجًا يربط وحدة التحكم بعرضها. تشرح هذه الصفحة كيفية إنشاء النطاق، ووظائف السلوك، والتسلسل الهرمي للعناصر الأبوية والفرعية، والفرق بينه وبين $rootScope، وكيفية تحديث الروابط بواسطة دورات التحديث.

  • 🔗 دور الربط: يقوم المتغير $scope بنقل متغيرات الأعضاء من وحدة التحكم إلى العرض، لذا تقوم القوالب بعرض البيانات دون لمس DOM بشكل مباشر.
  • ⚙️ وظائف السلوك: قم بإرفاق وظائف بـ $scope عندما يحتاج العرض إلى التفاعل مع النقرات أو تغييرات الإدخال أو أحداث المستخدم الأخرى.
  • 🌳 التسلسل الهرمي للنطاق: تقوم التوجيهات مثل ng-controller و ng-repeat بإنشاء نطاقات فرعية تعكس شجرة DOM الخاصة بالتطبيق.
  • 🌍 نطاق الوصول إلى $rootScope: يوجد نطاق واحد $rootScope لكل تطبيق ويتصرف ككائن عام يمكن لكل نطاق فرعي قراءته.
  • 🔍 دورة الهضم: يقوم $watch بتسجيل المستمعين، ويدخل $apply سياق تنفيذ AngularJS، ويقوم $digest بمقارنة القيم حتى يستقر النموذج.
  • 🚀 عادة الأداء: حافظ على بساطة تعبيرات المراقبة، وتجنب الوصول إلى DOM داخلها، واستدعِ $destroy على النطاقات التي لم تعد هناك حاجة إليها.

ما هو $Scope في AngularJS؟

ما هو النطاق $ في AngularJS؟

نطاق $ في AngularJS هو كائن مدمج يربط بشكل أساسي "وحدة التحكم" و"العرض". يمكن للمرء تحديد متغيرات الأعضاء في النطاق داخل وحدة التحكم والتي يمكن بعد ذلك الوصول إليها عن طريق العرض.

كل وحدة تحكم في AngularJS يحصل التطبيق على نسخة خاصة به من $scope من خلال حقن التبعية. أي شيء تقوم بإرفاقه بهذا الكائن يصبح مرئيًا للقالب الذي يتحكم فيه المتحكم، لذا فإن $scope يعمل كنموذج بيانات مشترك يقع بينك وبين Javaمنطق البرمجة النصية وعلامات HTML الخاصة بك.

النظر في المثال أدناه:

نطاق $ في AngularJS

angular.module('app',[]).controller('HelloWorldCtrl',
	function($scope)
	{
		$scope.message = "Hello World"
	});

Code التفسير:

  1. اسم الوحدة هو "التطبيق"
  2. اسم وحدة التحكم هو "HelloWorldCtrl"
  3. كائن النطاق هو الكائن الرئيسي الذي يتم استخدامه لتمرير المعلومات من وحدة التحكم إلى العرض.
  4. تمت إضافة متغير العضو إلى كائن النطاق

⚠️ تحذير بشأن بناء الجملة: استخدم .controller() تأخذ الدالة وسيطين، اسم وحدة التحكم ودالة المصنع، لذا يلزم وضع فاصلة بينهما. 'HelloWorldCtrl' و function($scope)حذف الفاصلة يُحدث خطأً Uncaught SyntaxError قبل أن يتم إطلاق AngularJS.

لا يمثل وجود وحدة تحكم واحدة وعرض واحد سوى نصف الصورة. فالتطبيقات الحقيقية تتضمن وحدات تحكم متداخلة، وقوائم متكررة، وعناصر واجهة مستخدم معاد استخدامها، مما يعني وجود نطاقات متعددة في آن واحد.

كيفية عمل التسلسل الهرمي للنطاق والوراثة في AngularJS

يحتوي كل تطبيق AngularJS على نطاق جذر واحد فقط، وقد يحتوي على أي عدد من النطاقات الفرعية. تقوم التوجيهات بإنشاء هذه النطاقات الفرعية وربطها بعنصر 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 التفسير:

  1. ParentCtrl يحدد siteName على نطاقها الخاص.
  2. ChildCtrl لا يحدد أبداً siteNameومع ذلك، لا يزال العنصر div الداخلي يطبع Guru99 لأن عملية البحث تصل إلى النطاق الأصل.
  3. lesson لا يوجد إلا في نطاق العنصر الفرعي، لذلك لا يمكن للعنصر الأب قراءته.

ما هي التوجيهات التي تُنشئ نطاقًا جديدًا؟

  • ng-controller: يُنشئ نطاقًا فرعيًا للعنصر الذي يتم وضعه عليه.
  • ng-repeat: يقوم بإنشاء نطاق فرعي واحد لكل تكرار، ولهذا السبب يمكن أن يحتوي كل صف على قيم مختلفة لنفس التعبير.
  • التوجيهات المخصصة: قد يطلبون منظارًا للأطفال، أو عزل نطاق لا يرث عمداً من نطاقه الأصلي.
  • توجيهات المكونات: أي شيء مسجل لدى .component() يتلقى المساعد دائمًا نطاقًا معزولًا.

لأن نطاقات العناصر الفرعية تقرأ من الأعلى إلى الأسفل، يتساءل المطورون غالبًا عن مكان وجود أعلى هذه السلسلة. يُطلق على هذا الكائن ذي المستوى الأعلى اسم $rootScope.

$scope مقابل $rootScope: ما الفرق؟

AngularJS $rootScope يمثل $rootScope نطاق التطبيق بأكمله. لا يمكن للتطبيق أن يحتوي إلا على $rootScope واحد، ويُستخدم كمتغير عام. كل $scope هو نطاق فرعي، و$rootScope هو النطاق الأصل في أعلى الشجرة. يقارن الجدول أدناه بين الكائنين.

البعد $scope $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 التفسير:

  1. نحن نقوم بإنشاء سلوك يسمى "الاسم الكامل". هذا السلوك عبارة عن دالة تقبل معلمتين (الاسم الأول واسم العائلة).
  2. يقوم السلوك بعد ذلك بإرجاع تسلسل هاتين المعلمتين.
  3. في العرض، نستدعي السلوك ونمرر قيمتين من "Guru"" و "99" والتي يتم تمريرها كمعاملات للسلوك.

إذا تم تنفيذ الأمر بنجاح، سيتم عرض الإخراج التالي عند تشغيل الكود الخاص بك في المتصفح.

الإخراج:

إعداد أو إضافة السلوك

سترى في المتصفح سلسلة من قيم كل من Guru و99 التي تم تمريرها إلى السلوك في مراقب .

يتم تحديث الروابط مثل الرابط المذكور أعلاه تلقائيًا، والآلية التي تجعل ذلك يحدث تستحق الفهم قبل أن يصبح التطبيق كبيرًا.

لماذا يُعدّ مراقبو النطاق ودورة التلخيص مهمين؟

يحافظ AngularJS على توافق العرض مع النطاق من خلال فحص التغييرات بدلاً من أحداث التغيير. وتُشغّل ثلاث واجهات برمجة تطبيقات للنطاق هذه العملية:

  • $watch: يسجل مستمعًا لتعبير معين. عمليات الاستيفاء مثل {{fullName}} قم بتسجيل المتابعين نيابةً عنك أثناء ربط القالب.
  • $apply: يدخل هذا الأمر سياق تنفيذ AngularJS، ويُقيّم الكود الخاص بك، ثم يُفعّل عملية التلخيص. ولا يُستخدم إلا داخل دوال رد الاتصال الخاصة بالأحداث المخصصة أو دوال رد الاتصال الخاصة بمكتبات الطرف الثالث، لأن التوجيهات المدمجة تستدعيه بالفعل.
  • ملخص: يقوم بفحص كل مراقب على $rootScope وأبنائه، ويقارن القيمة الحالية بالقيمة السابقة، ويكرر ذلك حتى يتوقف النموذج عن التغيير.

نظرًا لأن عملية التلخيص قد تُنفذ عدة دورات، يجب أن تظل تعابير المراقبة غير مكلفة. تجنب الوصول إلى DOM داخلها، لأن قراءة DOM أبطأ بكثير من قراءة... Javaخاصية البرنامج النصي.

يؤثر عمق المراقبة أيضاً على التكلفة. وتُعد المراقبة بالمرجع هي الأسرع، ولا تُلاحظ إلا عند استبدال القيمة بالكامل. $watchCollection تُلاحظ هذه العملية العناصر المضافة أو المحذوفة أو المعاد ترتيبها داخل مصفوفة أو كائن. تتطلب المراقبة حسب القيمة المرور عبر بنية متداخلة في كل عملية تجزئة، وهي الخيار الأكثر تكلفة، لذا يُنصح باللجوء إليها في النهاية.

الأسئلة الشائعة

لا يرث النطاق المعزول من النطاق الأصل بشكل نموذجي. تتلقى توجيهات المكونات التي تم إنشاؤها باستخدام المساعد .component() دائمًا نطاقًا معزولًا، مما يحافظ على استقلالية الأدوات القابلة لإعادة الاستخدام عن وحدة التحكم المحيطة ويمنع القراءة العرضية لخصائص الأصل.

يُرسل الأمر $emit حدث نطاق تصاعديًا عبر النطاقات الأصلية باتجاه $rootScope، بينما يُرسله الأمر $broadcast تنازليًا إلى كل نطاق فرعي. ويتم استقبال كلا الأمرين عند تشغيل $on. استخدم $broadcast باعتدال، لأنه يصل إلى كل نطاق فرعي.

استدعِ الدالة `scope.$destroy()` عندما لا تعود هناك حاجة إلى نطاق فرعي. هذا يوقف انتشار التحديث إلى النطاق ويسمح لجامع البيانات المهملة باستعادة نماذجه. قم أيضًا بإلغاء تسجيل المراقبين اليدويين، عن طريق استدعاء الدالة التي تُرجعها الدالة `$watch`.

مساعدون مثل مساعد الطيار جيثب يُنتجون نماذج نطاق سريعة، ومع ذلك لا يزالون يرتكبون أخطاءً مثل فاصلة مفقودة في تسجيل وحدة تحكم. تحقق من كل جزء مُنشأ مقابل النسخة الرسمية. توثيق نطاق AngularJS.

تقوم المساعدات المدعومة بالذكاء الاصطناعي بربط خصائص النطاق ($scope) بحقول فئة المكون، وإعادة كتابة منطق المراقبة ($watch) كإشارات أو تدفقات RxJS. قم بإقرانها مع المكتبات الرسمية. زاوي قم بتوثيق الاختبارات وتشغيل اختبارات الوحدة، لأن التحويلات التي تم إنشاؤها غالبًا ما تغفل عمليات البحث عن النطاق الموروث.

تلخيص هذه التدوينة بـ: