ذهبت لإجراء مقابلة أول من أمس، وسألني gg عن بعض المعلومات المتعلقة بـ js. وكان هناك سؤال حول استخدام الاتصال والتقديم. على الرغم من أنني استخدمت طريقة الاتصال منذ 365 يومًا، إلا أنني ما زلت غير قادر على الإجابة عليها في ذلك الوقت سألخصها بعمق اليوم.
استدعاء وتطبيق، وظيفتهم هي ربط الوظيفة بكائن آخر لتشغيله.
تعريفات التنسيق والمعلمات لكليهما:
call( thisArg [, arg1, arg2, ... ] ); // قائمة المعلمات, arg1, arg2, ...
Apply(thisArg [, argArray] ); // مصفوفة المعلمات, argArray
سيتم تعيين thisArg للمؤشر الموجود داخل الوظيفتين أعلاه، والذي يمكنه تحقيق الغرض من تشغيل الوظيفة كطريقة لكائن آخر.
1. الاستخدام البسيط للدعوة
أولاً، دعونا نلقي نظرة على مثال بسيط (استدعاء):
انسخ رمز الكود كما يلي:
<!نوع الوثيقة html>
<أتش تي أم أل>
<الرأس>
<title> طلب الاتصال </title>
</الرأس>
<الجسم>
<نوع الإدخال = "نص" معرف = "idTxt" قيمة = "نص الإدخال">
<نوع البرنامج النصي = "نص/جافا سكريبت">
قيمة فار = "فار عالمي"؛
الدالة mFunc()
{
this.value = "العضو فار";
}
الدالة gFunc()
{
تنبيه (هذه القيمة)؛
}
window.gFunc();// إظهار gFunc، العمومي var
gFunc.call(window);// show gFunc, global var
gFunc.call(new mFunc());// عرض mFunc، العضو var
gFunc.call(document.getElementById('idTxt'));// إظهار العنصر، إدخال النص
</script>
<لغة البرمجة = "جافا سكريبت">
فار فونك = وظيفة جديدة ()
{
this.a = "func";
}
فار func2 = الوظيفة(س)
{
var a = "func2";
تنبيه (هذا. أ)؛
تنبيه (خ)؛
}
func2.call(func, "func2");// عرض func و func2
</script>
</الجسم>
</html>
وبعد ذلك تكون نتائج التشغيل كما يلي:
فار العالميةفار العالمية
عضو فار
إدخال النص
func
func2
بيئة الاختبار: جوجل كروم10.0.648.45
وأخيرا، تحليل النتائج
1. تستدعي نافذة الكائن العامة الدالة gFunc، ويشير هذا إلى كائن النافذة، لذا فإن this.value هي var عمومية.
2. تستدعي الدالة gFunc طريقة الاستدعاء، ويشير هذا إلى كائن نافذة المعلمة الأولى افتراضيًا، لذا فإن this.value هي أيضًا قيمة var عامة.
3. تستدعي الدالة gFunc أسلوب الاستدعاء، وهذا الإعداد الافتراضي هو المعلمة الأولى new mFunc()، وهو كائن mFunc. لذلك، this.value هو متغير العضو mFunc.
4. تستدعي الدالة gFunc طريقة الاتصال بشكل افتراضي، ويشير هذا إلى عنصر التحكم في نص إدخال المعلمة الأولى، أي عنصر التحكم بالمعرف = 'idTxt'، لذلك فإن هذه القيمة هي نص إدخال القيمة لعنصر تحكم الإدخال.
5. تستدعي الدالة func2 أسلوب الاستدعاء، وهذا هو الإعداد الافتراضي لكائن الدالة func للمعلمة الأولى، لذا فإن this.value هي this.a، وهي func.
6. تستدعي الدالة func2 طريقة الاستدعاء، تنتمي المعلمة الثانية إلى معلمة كائن الوظيفة func2، لذا فإن التنبيه (x) هو المعلمة الثانية func2.
2. استخدام الميراث وتحسينه
يستخدم Node.js الاستدعاء لمحاكاة الميراث
رمز الاختبار:
انسخ رمز الكود كما يلي:
<!نوع الوثيقة html>
<أتش تي أم أل>
<الرأس>
استدعاء <title> - التقدم بطلب للحصول على وراثة </title>
</الرأس>
<الجسم>
<نوع البرنامج النصي = "نص/جافا سكريبت">
الدالة baseA()// الفئة الأساسية A
{
this.member = "baseA member";
this.showSelfA = الدالة()
{
window.alert(this.member);
}
}
الدالة baseB()// الفئة الأساسية B
{
this.member = "العضو الأساسي";
this.showSelfB = وظيفة ()
{
window.alert(this.member);
}
}
الدالة ExtendAB()// وراثة الفئة من A وB
{
baseA.call(this);// استدعاء A
baseB.call(this);// استدعاء B
}
window.onload = وظيفة ()
{
var Extend = new ExtendAB();
تمديد.showSelfA();// عرض أ
تمديد.showSelfB();// عرض ب
}
</script>
</الجسم>
</html>
نتائج التشغيل هي كما يلي:عضو قاعدة ب
عضو قاعدة ب
بيئة الاختبار: جوجل كروم10.0.648.45
تحليل النتيجة:
يجب أن تكون النتيجة المتوقعة هي إخراج عضو baseA وعضو baseB، لكن الإخراج الفعلي هو عضو baseB وعضو baseB.
(تم اختباره في IE9، 8، 6، Maxthon، Chrome، FF، Opera، Safari، 360 ومتصفحات أخرى، والنتيجة هي الأخيرة: عضو BaseB)
في هذه المرحلة، الآلة ليست مخطئة، الأمر الذي يتطلب منا إجراء تحليل متعمق
قد نعتقد بسهولة أن السبب هو أن هذا يشير إلى الكائن baseB مرتين، ولكن هل هذا هو الحال حقًا؟
من أجل استكشاف الجوهر، استخدمنا أداة تصحيح الأخطاء في متصفح Chrome لتعيين نقاط التوقف وتصحيح الأخطاء، ووجدنا ما يلي:
عندما يتم استدعاء Extend.showSelfA();، فهذا يشير إلى ExtendAB (وليس إلى الكائن baseB كما توقعنا مرتين)
السبب الحقيقي هو أن العضو المتغير العضو في كائن ExtendAB يتم استبداله بواسطة العضو العضو baseB عندما يتم إنشاء مثيل له بواسطة baseB.call(this); عضو قاعدة ب.
بالطبع، يمكننا أيضًا تعديل الكود الأساسي أعلاه قليلًا للتحقق من صحة تحليل تصحيح الأخطاء لدينا:
انسخ رمز الكود كما يلي:
الدالة baseA()// الفئة الأساسية A
{
this.memberA = "baseA member"; // تم تغيير العضو إلى العضو A لتمييز العضو في baseB
this.showSelfA = الدالة()
{
window.alert(this.memberA);// عرض العضو أ
}
}
قم بتشغيل المتصفحات مثل الكروم مرة أخرى، وكانت النتائج كما يلي:
عضو أساسي
عضو قاعدة ب
النتائج هي نفس توقعاتنا، كما تتحقق معلومات تصحيح أخطاء Chrome من صحتها:
تحسينات الميراث (النموذج الأولي)
طريقة الميراث المحاكاة أعلاه ليست الأفضل بعد التحليل الدقيق.
لأنه في كل مرة يتم فيها تعريف طريقة عضو في دالة (فئة)، فإنها ستؤدي إلى نسخة من المثيل، حتى تتمكن من استخدام النموذج الأولي لإجراء التحسينات.
أمثلة التحسينات هي كما يلي:
انسخ رمز الكود كما يلي:
<!نوع الوثيقة html>
<أتش تي أم أل>
<الرأس>
استدعاء <title> - تقدم بطلب للحصول على النموذج الأولي </title>
</الرأس>
<الجسم>
<نوع البرنامج النصي = "نص/جافا سكريبت">
فاركلاس = {
إنشاء: وظيفة () // إنشاء وظيفة
{
وظيفة الإرجاع ()
{
this.initialize.apply(this,حجج);
}
}
};
var Person = Class.create();// إنشاء شخص فئة
Person.prototype = {// تهيئة النموذج الأولي
التهيئة: الوظيفة (obj1، obj2)
{
this.obj1 = obj1;
this.obj2 = obj2;
},
إظهار الذات: وظيفة ()
{
تنبيه ("obj: " + this.obj1 + " و " + this.obj2)؛
}
}
// فئة المثيل
var person = new Person("man", "women");// اثنين من المعلمات
person.showSelf();// إظهار الشخص
</script>
</الجسم>
</html>
نتائج التشغيل هي كما يلي:
obj: الرجال والنساء