تمرير حسب القيمة مقابل. تمرير بالرجوع إليه
المكالمة حسب القيمة هي استراتيجية التقييم الأكثر استخدامًا: المعلمات الرسمية للدالة هي نسخ من المعلمات الفعلية التي تم تمريرها عند استدعاء. لن يؤثر تعديل قيمة المعلمة الرسمية على المعلمة الفعلية.
عند المرور حسب المرجع (اتصل بالرجوع) ، تتلقى المعلمات الرسمية للدالة مرجعًا ضمنيًا للمعلمة الفعلية ، بدلاً من نسخة. هذا يعني أنه إذا تم تعديل قيمة معلمة الوظيفة ، فسيتم تعديل المعلمة الفعلية أيضًا. كلاهما يشير إلى نفس القيمة.
إن التمرير بالرجوع يجعل تتبع مكالمات الوظائف أكثر صعوبة وأحيانًا يسبب بعض الأخطاء الدقيقة.
تمرير بالقيمة نظرًا لأن النسخ المتماثلة يتم استنساخها في كل مرة ، يكون الأداء أقل بالنسبة لبعض الأنواع المعقدة. كلتا الطريقتين لتمرير القيم لها مشاكل خاصة بها.
دعونا أولاً نلقي نظرة على مثال C لفهم الفرق بين المرور بالقيمة والمرجع:
نسخة الكود كما يلي:
تعديل باطل (int p ، int * q)
{
P = 27 ؛ // تمرير حسب القيمة - P عبارة عن نسخة من المعلمة الفعلية A ، يتم تعديل P فقط
*س = 27 ؛ // Q هو إشارة إلى B ، ويتم تعديل كلا Q و B
}
int main ()
{
int a = 1 ؛
int b = 1 ؛
تعديل (A ، & B) ؛ // تمريرة بالقيمة ، ب. بالمرجع ،
// لم يتغير ، لقد تغير ب
العودة (0) ؛
}
هنا يمكننا أن نرى:
A => عندما يتم تمرير P حسب القيمة ، فإن تعديل قيمة المعلمة الرسمية P لا يؤثر على المعلمة الفعلية A ، P هي مجرد نسخة من A.
B => Q يتم تمريره بالرجوع إليه. عند تعديل قيمة المعلمة الرسمية Q ، فإنه يؤثر أيضًا على قيمة المعلمة الفعلية ب.
استكشف كيف يتم تمرير قيمة JS
يتم تمرير النوع الأساسي من JS بالقيمة.
نسخة الكود كما يلي:
var a = 1 ؛
وظيفة foo (x) {
x = 2 ؛
}
فو (أ) ؛
console.log (a) ؛ // لا يزال 1 ، لا يتأثر بتعيين x = 2
دعونا نلقي نظرة على الكائن:
نسخة الكود كما يلي:
var obj = {x: 1} ؛
وظيفة foo (o) {
الثور = 3 ؛
}
فو (OBJ) ؛
console.log (obj.x) ؛ // 3 ، معدلة!
اشرح O و OBJ هما نفس الكائن ، و O ليس نسخة من OBJ. لذلك لم يتم تمريرها بالقيمة. ولكن هل هذا يعني أن كائنات JS قد تم تمريرها بالرجوع إليها؟ دعونا نلقي نظرة على الأمثلة التالية:
نسخة الكود كما يلي:
var obj = {x: 1} ؛
وظيفة foo (o) {
س = 100 ؛
}
فو (OBJ) ؛
console.log (obj.x) ؛ // لا يزال 1 ، لم يتم تعديل OBJ إلى 100.
إذا تم تمريره بالرجوع إليه ، فقم بتعديل قيمة المعلمة الرسمية O ، فيجب أن يؤثر على المعلمة الفعلية. لكن تعديل قيمة o هنا لا يؤثر على OBJ. لذلك ، لا يتم تمرير الكائنات في JS بالرجوع إليها. فكيف يتم تمرير قيمة الكائن في JS؟
تمرير المكالمة عن طريق المشاركة
لكي تكون دقيقة ، يتم تمرير الأنواع الأساسية في JS حسب القيم ، ويتم تمرير أنواع الكائنات عن طريق المشاركة (استدعاء عن طريق المشاركة ، والتي تسمى أيضًا Object ومشاركتها بواسطة Object). تم اقتراحه لأول مرة من قبل باربرا ليسكوف. في لغة غلو 1974. يتم استخدام استراتيجية التقييم هذه في بيثون ، جافا ، روبي ، JS ولغات أخرى.
الهدف من هذه الاستراتيجية هو أنه عندما تمر وظيفة ما ، تقبل الوظيفة نسخة من مرجع الوسيطة الفعلية للكائن (لا نسخة من الكائن الذي تم تمريره حسب القيمة ، ولا مرجع ضمني تم تمريره بالرجوع إليه). الفرق بينه والمرور بالرجوع إليه هو أن تعيين معلمات الوظيفة في تمريرة مشتركة لن يؤثر على قيمة المعلمة الفعلية. كما في المثال التالي ، لا يمكن تعديل قيمة OBJ عن طريق تعديل قيمة المعلمة الرسمية O.
نسخة الكود كما يلي:
var obj = {x: 1} ؛
وظيفة foo (o) {
س = 100 ؛
}
فو (OBJ) ؛
console.log (obj.x) ؛ // لا يزال 1 ، لم يتم تعديل OBJ إلى 100.
ومع ذلك ، على الرغم من أن المرجع هو نسخة ، فإن الكائن المشار إليه هو نفسه. يشاركون نفس الكائن ، لذلك سيؤثر تعديل قيمة السمة لكائن المعلمة الرسمي أيضًا على قيمة السمة للمعلمة الفعلية.
نسخة الكود كما يلي:
var obj = {x: 1} ؛
وظيفة foo (o) {
الثور = 3 ؛
}
فو (OBJ) ؛
console.log (obj.x) ؛ // 3 ، معدلة!
بالنسبة لأنواع الكائنات ، نظرًا لأن الكائن قابل للتغيير ، فإن تعديل الكائن نفسه سيؤثر على مشاركة النسخة المرجعية والمرجعية للكائن. بالنسبة للأنواع الأساسية ، نظرًا لأن كلاهما غير قابل للتغيير ، لا يوجد فرق بين المرور عن طريق المشاركة والتمرير حسب القيمة (استدعاء القيمة) ، لذلك فإن أنواع JS الأساسية تتماشى مع التمرير بالقيمة والتوافق مع النجاح بالمشاركة.
var a = 1 ؛ // 1 هو رقم النوع ، var v var b = a ؛ ب = 6 ؛
وفقًا لاستراتيجية التقييم التي تم تمريرها بواسطة المشاركة ، فإن A و B هما مرجعان مختلفتان (B عبارة عن نسخة مرجعية من A) ، ولكنها تشير إلى نفس القيمة. نظرًا لأن رقم النوع الأساسي 1 هنا غير قابل للتغيير ، فلا يوجد فرق بين المرور بالقيمة والتمرير بالمشاركة هنا.
خصائص غير قابلة للتغيير للأنواع الأساسية
الأنواع الأساسية غير قابلة للتغيير ، والكائنات الوحيدة قابلة للتغيير. على سبيل المثال ، القيم الرقمية 100 ، القيم المنطقية صحيحة ، خاطئة ، وتعديل هذه القيم (على سبيل المثال ، تحول 1 إلى 3 ، وتحول صحيح إلى 100) لا معنى له. ما يسهل إساءة فهمه هو سلسلة في JS. في بعض الأحيان ، نحاول "تغيير" محتويات السلسلة ، ولكن في JS ، أي عملية "تعديل" يبدو أنها قيمة سلسلة هي في الواقع إنشاء قيمة سلسلة جديدة.
نسخة الكود كما يلي:
var str = "ABC" ؛
str [0] ؛ // "أ"
str [0] = "D" ؛
شارع // لا يزال "ABC" ؛ المهمة غير صالحة. لا توجد طريقة لتعديل محتوى السلسلة
الكائن مختلف ، الكائن متغير.
نسخة الكود كما يلي:
var obj = {x: 1} ؛
obj.x = 100 ؛
var o = obj ؛
الثور = 1 ؛
obj.x ؛ // 1 ، معدلة
o = صحيح ؛
obj.x ؛ // 1 ، لن يتغير بسبب o = صحيح
هنا يتم تعريف المتغير OBJ ، والقيمة هي كائن ، ثم يتم تعيين قيمة خاصية OBJ.x على 100. ثم تحديد متغير آخر O ، والقيمة لا تزال هذا الكائن. في هذا الوقت ، تشير قيم المتغيرين OBJ و O إلى نفس الكائن (مشاركة مرجع إلى نفس الكائن). لذلك ، فإن تعديل محتوى الكائن له تأثير على كل من OBJ و O. ومع ذلك ، لا يتم تمرير الكائن بالرجوع إليه. يتم تعديل قيمة O بواسطة O = صحيح ولن تؤثر على OBJ.