لماذا تم إهمال خاصية الوسيطات.callee.caller في جافا سكريبت؟

StackOverflow https://stackoverflow.com/questions/103598

  •  01-07-2019
  •  | 
  •  

سؤال

لماذا كان arguments.callee.caller الخاصية مهملة في جافا سكريبت؟

تمت إضافته ثم إهماله في JavaScript، ولكن تم حذفه تمامًا بواسطة ECMAScript.لقد دعمته بعض المتصفحات (Mozilla، IE) دائمًا وليس لديها أي خطط على الخريطة لإزالة الدعم.اعتمد آخرون (Safari وOpera) دعمًا لها، لكن الدعم على المتصفحات القديمة لا يمكن الاعتماد عليه.

هل هناك سبب وجيه لوضع هذه الوظيفة القيمة في طي النسيان؟

(أو بدلاً من ذلك، هل هناك طريقة أفضل للتحكم في وظيفة الاتصال؟)

هل كانت مفيدة؟

المحلول

لم تكن الإصدارات المبكرة من JavaScript تسمح بتعبيرات الوظائف المسماة، ولهذا السبب لم نتمكن من إنشاء تعبيرات دالة متكررة:

 // This snippet will work:
 function factorial(n) {
     return (!(n>1))? 1 : factorial(n-1)*n;
 }
 [1,2,3,4,5].map(factorial);


 // But this snippet will not:
 [1,2,3,4,5].map(function(n) {
     return (!(n>1))? 1 : /* what goes here? */ (n-1)*n;
 });

للالتفاف حول هذا، arguments.callee تمت إضافته حتى نتمكن من القيام بما يلي:

 [1,2,3,4,5].map(function(n) {
     return (!(n>1))? 1 : arguments.callee(n-1)*n;
 });

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

var global = this;
var sillyFunction = function (recursed) {
    if (!recursed)
        return arguments.callee(true);
    if (this !== global)
        alert("This is: " + this);
    else
        alert("This is the global");
}
sillyFunction();

على أية حال، قام EcmaScript 3 بحل هذه المشكلات من خلال السماح بتعبيرات الوظائف المسماة، على سبيل المثال:

 [1,2,3,4,5].map(function factorial(n) {
     return (!(n>1))? 1 : factorial(n-1)*n;
 });

وهذا له فوائد عديدة:

  • يمكن استدعاء الوظيفة مثل أي وظيفة أخرى من داخل التعليمات البرمجية الخاصة بك.

  • لا تلوث مساحة الاسم.

  • قيمة ال this لم يتغير.

  • إنه أكثر أداءً (الوصول إلى ملف كائن الحجج غالي).

عفوًا،

أدركت للتو أنه بالإضافة إلى كل شيء آخر كان السؤال حول arguments.callee.caller, ، أو بشكل أكثر تحديدا Function.caller.

في أي وقت من الأوقات، يمكنك العثور على المتصل الأعمق لأي وظيفة في المكدس، وكما قلت أعلاه، فإن النظر إلى مكدس الاستدعاءات له تأثير رئيسي واحد:فهو يجعل عددًا كبيرًا من التحسينات مستحيلاً، أو أكثر صعوبة بكثير.

على سبيل المثال.إذا لم نتمكن من ضمان أن وظيفة f لن تستدعي وظيفة غير معروفة، فلا يمكن تضمينها f.هذا يعني في الأساس أن أي موقع اتصال قد يكون غير قابل للتضمين بشكل تافه يتراكم فيه عدد كبير من الحراس، خذ:

 function f(a, b, c, d, e) { return a ? b * c : d * e; }

إذا لم يتمكن مترجم js من ضمان أن جميع الوسائط المقدمة هي أرقام عند إجراء الاستدعاء، فإنه يحتاج إما إلى إدراج عمليات فحص لجميع الوسائط قبل الكود المضمن، أو لا يمكنه تضمين الوظيفة.

الآن في هذه الحالة بالذات، يجب أن يكون المترجم الذكي قادرًا على إعادة ترتيب عمليات التحقق لتكون أكثر مثالية وعدم التحقق من أي قيم لن يتم استخدامها.ولكن في كثير من الحالات، يكون هذا غير ممكن، وبالتالي يصبح من المستحيل تضمينه.

نصائح أخرى

arguments.callإي.callإيه يكون لا تم إهماله، على الرغم من أنه يستفيد من Function.callإيه ملكية.(arguments.callإي سوف أعطيك فقط إشارة إلى الوظيفة الحالية)

  • Function.callإيه, ، على الرغم من أنه غير قياسي وفقًا لـ ECMA3، إلا أنه يتم تنفيذه عبر جميع المتصفحات الرئيسية الحالية.
  • arguments.callإيه يكون استنكرت لصالح Function.callإيه, ، ولا يتم تنفيذه في بعض المتصفحات الرئيسية الحالية (مثل.فايرفوكس 3).

لذا فإن الوضع ليس مثاليًا، ولكن إذا كنت تريد الوصول إلى وظيفة الاتصال في Javascript عبر جميع المتصفحات الرئيسية، فيمكنك استخدام Function.callإيه الخاصية، إما يتم الوصول إليها مباشرة من خلال مرجع وظيفة مسماة، أو من داخل وظيفة مجهولة عبر arguments.callإي ملكية.

فمن الأفضل للاستخدام وظائف مسماة من الحجج.

 function foo () {
     ... foo() ...
 }

أفضل من

 function () {
     ... arguments.callee() ...
 }

سيكون للوظيفة المسماة إمكانية الوصول إلى المتصل بها من خلال المتصل ملكية:

 function foo () {
     alert(foo.caller);
 }

وهو أفضل من

 function foo () {
     alert(arguments.callee.caller);
 }

يرجع الإيقاف إلى ECMAScript الحالي مبادئ التصميم.

مجرد امتداد.تتغير قيمة "هذا" أثناء العودية.في المثال التالي (المعدل)، يحصل العامل على الكائن {foo:true}.

[1,2,3,4,5].map(function factorial(n) {
  console.log(this);
  return (!(n>1))? 1 : factorial(n-1)*n;
},     {foo:true}     );

العامل الذي يتم استدعاؤه لأول مرة يحصل على الكائن، لكن هذا ليس صحيحًا بالنسبة للاستدعاءات العودية.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top