سؤال

هناك نوعان من أنماط الإغلاق الشائعة في جافا سكريبت.أول ما أتصل به منشئ مجهول:

new function() { 
  var code...
}

و ال وظيفة التنفيذ المضمنة:

(function() {
  var code...
})();

هل هناك اختلافات في السلوك بين هذين؟هل أحدهما "أفضل" على الآخر؟

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

المحلول

ستنفذ كلتا الحالتين الدالة، والفرق الحقيقي الوحيد هو ما قد تكون عليه القيمة المرجعة للتعبير، وما ستكون قيمة "هذا" داخل الدالة.

السلوك في الأساس

new expression

يعادل بشكل فعال

var tempObject = {};
var result = expression.call(tempObject);
if (result is not an object)
    result = tempObject;

على الرغم من أن tempObject وresult هما بالطبع قيمتان عابرتان لا يمكنك رؤيتهما أبدًا (إنهما تفاصيل التنفيذ في المترجم)، ولا توجد آلية JS لإجراء التحقق من "ليس كائنًا".

بشكل عام "الوظيفة الجديدة () { ..}" ستكون الطريقة أبطأ بسبب الحاجة إلى إنشاء هذا الكائن للمنشئ.

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

يحرر:شيء واحد أدركت أنني فاتني من هذا هو أن tempObject سوف تحصل expressionالنموذج الأولي، على سبيل المثال.(قبل expression.call) tempObject.__proto__ = expression.prototype

نصائح أخرى

@حربة:الأول يتم تنفيذه أيضًا.قارنه مع مُنشئ مسمى:

function Blah() {
    alert('blah');
}
new Bla();

وهذا في الواقع أيضًا ينفذ التعليمات البرمجية.وينطبق الشيء نفسه على المنشئ المجهول ...

ولكن لم يكن هذا هو السؤال ;-)

يقوم كلاهما بإنشاء إغلاق عن طريق تنفيذ كتلة التعليمات البرمجية.من حيث الأسلوب فأنا أفضل الثاني لعدة أسباب:

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

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

حسنًا، لقد قمت بإنشاء صفحة مثل هذه:

<html>
<body>
<script type="text/javascript">
var a = new function() { 
  alert("method 1");

  return "test";
};

var b = (function() {
  alert("method 2");

  return "test";
})();

alert(a);  //a is a function
alert(b);  //b is a string containing "test"

</script>
</body>
</html>

والمثير للدهشة (بالنسبة لي على أي حال) أنه نبه كلاً من "الطريقة 1" والطريقة 2".لم أكن أتوقع أن يتم تنبيه "الطريقة الأولى".وكان الفرق هو ما كانت عليه قيم a وb.كانت a هي الدالة نفسها، بينما كانت b هي السلسلة التي أرجعتها الدالة.

المثال الثاني سوف ينفذ الوظيفة بعد إنشائها.

يحرر:هذا ليس صحيحا حقا.

نعم، هناك اختلافات بين الاثنين.

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

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

مثال:

<html>
<body>
<script type="text/javascript">

new function() { 
a = "Hello";
alert(a + " Inside Function");
};

alert(a + " Outside Function");

(function() { 
var b = "World";
alert(b + " Inside Function");
})();

alert(b + " Outside Function");
</script>
</body>
</html>

في الكود أعلاه يكون الإخراج مثل:

مرحبا داخل الوظيفة
مرحبًا بالوظيفة الخارجية
وظيفة العالم الداخلي

...ثم تحصل على خطأ لأن "b" لم يتم تعريفه خارج الوظيفة!

لذلك أرى أن الطريقة الثانية هي الأفضل..أكثر أمانا!

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