لماذا تحتاج إلى استدعاء وظيفة مجهولة على نفس السطر؟

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

سؤال

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

// Create a new anonymous function, to use as a wrapper
(function(){
    // The variable that would, normally, be global
    var msg = "Thanks for visiting!";

    // Binding a new function to a global object
    window.onunload = function(){
        // Which uses the 'hidden' variable
        alert( msg );
    };
// Close off the anonymous function and execute it
})();

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

(function (msg){alert(msg)})('SO');

سؤالي هو أي نوع من السحر يحدث هنا؟ اعتقدت أنه عندما كتبت:

(function (msg){alert(msg)})

ثم سيتم إنشاء وظيفة جديدة لم تكشف عن اسمها مثل الوظيفة "" (msg) ...

ولكن بعد ذلك لماذا لا يعمل هذا؟

(function (msg){alert(msg)});
('SO');

لماذا يجب أن تكون في نفس الخط؟

هل يمكن أن توجه بي بعض المشاركات أو أعطني تفسيرا؟

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

المحلول

إسقاط الفاصلة المنقوطة بعد تعريف الوظيفة.

(function (msg){alert(msg)})
('SO');

أعلاه يجب أن تعمل.

الصفحة التجريبية: https://jsfiddle.net/e7ooeq6m/

لقد ناقشت هذا النوع من النمط في هذا المنشور:

جيس وأسئلة $

تعديل:

إذا نظرت في ECMA Script المواصفات, ، هناك 3 طرق يمكنك تحديد وظيفة. (صفحة 98، قسم الوظيفة القسم 13)

1. استخدام منشئ الوظيفة

var sum = new Function('a','b', 'return a + b;');
alert(sum(10, 20)); //alerts 30

2. استخدام إعلان الوظيفة.

function sum(a, b)
{
    return a + b;
}

alert(sum(10, 10)); //Alerts 20;

3. وظيفة التعبير

var sum = function(a, b) { return a + b; }

alert(sum(5, 5)); // alerts 10

لذلك قد تسأل، ما الفرق بين الإعلان والتعبير؟

من مواصفات البرنامج النصي ECMA:

وظيفة الدوالة: معرف الدالة (FormalParameterList) {وظيفة}

FormationExpression: وظيفة المعرف الوظيفة (FormalParameterListOpt) {documentbody}

إذا لاحظت، "المعرف" هو اختياري للتعبير الوظيفي. وعندما لا تعطي معرفا، يمكنك إنشاء وظيفة مجهولة. هذا لا يعني أنه لا يمكنك تحديد معرف.

هذا يعني التالي هو صالح.

var sum = function mySum(a, b) { return a + b; }

النقطة المهمة التي يجب ملاحظتها هي أنه يمكنك استخدام "Mysum" فقط داخل جسم وظيفة MySum، وليس في الخارج. انظر المثال التالي:

var test1 = function test2() { alert(typeof test2); }

alert(typeof(test2)); //alerts 'undefined', surprise! 

test1(); //alerts 'function' because test2 is a function.

عرض حي

قارن هذا إلى

 function test1() { alert(typeof test1) };

 alert(typeof test1); //alerts 'function'

 test1(); //alerts 'function'

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

عندما يكون لديك رمز مثل،

    function(msg) { alert(msg); }

قمت بإنشاء تعبير وظيفة. ويمكنك تنفيذ هذا التعبير الوظيفة عن طريق التفاف عليه داخل الأقواس.

    (function(msg) { alert(msg); })('SO'); //alerts SO.

نصائح أخرى

يطلق عليه وظيفة استدعاء ذاتيا.

ما تفعله عند الاتصال (function(){}) يعيد كائن وظيفة. عند إلحاقك () لذلك، يتم الاحتجاج به وأي شيء في الجسم المنفذ. ال ; يدل على نهاية البيان، ولهذا السبب فشل الاحتجاج الثاني.

شيء واحد وجدته مربكا هو أن "()" هم مشغلي التجمع.

هنا هي وظيفةك المعلنة الأساسية.

السابق. 1:

var message = 'SO';

function foo(msg) {
    alert(msg);
}

foo(message);

وظائف هي الكائنات، ويمكن تجميعها. لذلك دعونا رمي الشجاعة حول الوظيفة.

السابق. 2:

var message = 'SO';

function foo(msg) {  //declares foo
    alert(msg);
}

(foo)(message);     // calls foo

الآن بدلا من التصريح واليمين في الدعوة نفس الوظيفة، يمكننا استخدام الاستبدال الأساسي لإعلانها ونحن نسميها.

السابق. 3.

var message = 'SO';

(function foo(msg) {
    alert(msg);
})(message);          // declares & calls foo

أخيرا، ليس لدينا حاجة لذلك فو الإضافي لأننا لا نستخدم الاسم للاتصال به! الوظائف يمكن أن تكون مجهولة.

السابق. 4.

var message = 'SO';

(function (msg) {   // remove unnecessary reference to foo
    alert(msg);
})(message);

للإجابة على سؤالك، ارجع إلى مثال 2. يعلن سطرك الأول بعض الوظائف المسجلة والجماعات، لكنه لا يتصل به. المجموعات السطرية الثانية سلسلة. كلاهما لا يفعل شيئا. (مثال فنسنت الأول.)

(function (msg){alert(msg)});  
('SO');                       // nothing.

(foo); 
(msg); //Still nothing.

ولكن

(foo)
(msg); //works

وظيفة مجهولة ليست وظيفة مع الاسم "". انها مجرد وظيفة دون اسم.

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

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

إليك وظيفة ورقم، وليس ملزمة، لا يفعلون شيئا ولا يمكن استخدامها أبدا:

function(){ alert("plop"); }
2;

لذلك علينا تخزينها في متغير لتكون قادرا على استخدامها، تماما مثل أي قيمة أخرى:

var f = function(){ alert("plop"); }
var n = 2;

يمكنك أيضا استخدام السكر التجليئي لربط الوظيفة بمتغير:

function f(){ alert("plop"); }
var n = 2;

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

(function(){ alert("plop"); })(); // will display "plop"
alert(2 + 3); // will display 5

هنا، وظيفتي وأرقامي ليست ملزمة بمتغير، ولكن لا يزال بإمكانهم استخدامها.

وقال مثل هذا، يبدو أن وظيفة الاستدعاء الذاتي ليس لها قيمة حقيقية. ولكن عليك أن تضع في اعتبارك أن نطاق جافا سكريبت محدد هو الوظيفة وليس الكتلة ({}).

لذلك وظيفة استدعاء الذات لديها في الواقع نفس المعنى مثل كتلة C ++ أو C # أو Java. مما يعني أن المتغير الذي تم إنشاؤه الداخل لن "تسرب" خارج النطاق. هذا مفيد جدا في جافا سكريبت من أجل عدم تلوث النطاق العالمي.

انها مجرد كيفية عمل جافا سكريبت. يمكنك إعلان وظيفة اسمه:

function foo(msg){
   alert(msg);
}

والاتصال به:

foo("Hi!");

أو، يمكنك إعلان وظيفة مجهولة:

var foo = function (msg) {
    alert(msg);
}

وندعو ذلك:

foo("Hi!");

أو، لا يمكنك فقط ربط الوظيفة باسم:

(function(msg){
   alert(msg);
 })("Hi!");

الوظائف يمكن أيضا إرجاع الوظائف:

function make_foo() {
    return function(msg){ alert(msg) };
}

(make_foo())("Hi!");

لا يستحق أي متغيرات محددة ب "فار" في الجسم make_foo سيتم إغلاقها من قبل كل وظيفة عاد من قبل make_foo. وبعد هذا إغلاق، وهذا يعني أن أي تغيير يتم إجراؤه على القيمة بواسطة وظيفة واحدة سيكون مرئيا من قبل آخر.

يتيح لك هذا تثبيت المعلومات، إذا كنت ترغب في:

function make_greeter(msg){
    return function() { alert(msg) };
}

var hello = make_greeter("Hello!");

hello();

انها مجرد ما تقريبا كل لغة برمجة ولكن جافا يعمل.

الرمز الذي تظهره،

(function (msg){alert(msg)});
('SO');

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

var f = (function (msg){alert(msg)});
f('SO');

لاحظ أنه من خلال تخزين وظيفة مجهولة (وظيفة LambDA) في متغير، فإنك تعطيها بشكل فعال اسم. وبالتالي يمكنك فقط تحديد وظيفة منتظمة:

function f(msg) {alert(msg)};
f('SO');

باختصار التعليقات السابقة:

function() {
  alert("hello");
}();

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

(function() {
  alert("hello");
})();

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

هنالك جيد جدا مناقشة وظيفة جافا سكريبت.

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

alert(
    {foo: "I am foo", bar: "I am bar"}.foo
); // alerts "I am foo"

المتعلقة الوظائف. لأنها كائنات، التي ترث من الوظيفة. النمط الأسماك، يمكننا القيام بأشياء مثل:

Function.prototype.foo = function () {
    return function () {
        alert("foo");
    };
};

var bar = (function () {}).foo();

bar(); // alerts foo

وأنت تعرف، ليس لدينا حتى لوظائف محيطية مع قوسين من أجل تنفيذها. على أي حال، طالما أننا نحاول تعيين النتيجة إلى متغير.

var x = function () {} (); // this function is executed but does nothing

function () {} (); // syntax error

شيء آخر يمكنك القيام به مع وظائف، بمجرد إعلانها، هو استدعاء new المشغل عليهم والحصول على كائن. ما يلي ما يعادل:

var obj = new function () {
    this.foo = "bar";
};

var obj = {
    foo : "bar"
};

هناك وظيفة جافا سكريبت أخرى واحدة لديها. إذا كنت ترغب في استدعاء نفس الوظيفة المجهولة بشكل متكرر.

(function forInternalOnly(){

  //you can use forInternalOnly to call this anonymous function
  /// forInternalOnly can be used inside function only, like
  var result = forInternalOnly();
})();

//this will not work
forInternalOnly();// no such a method exist

فهمي لسؤال Asker هو:

كيف هذا العمل السحري:

(function(){}) ('input')   // Used in his example

ربما أكون مخطئا. ومع ذلك، فإن الممارسة المعتادة التي يعرفها الناس هي:

(function(){}('input') )

السبب هو مثل أن أقواس جافا سكريبت AKA (), ، لا يمكن أن تحتوي على بيانات وعندما يواجه المحلل المحلل الكلمة الرئيسية الوظيفة، فإنه يعرف تحليله كتعبير وظيفة وليس إعلان دالة.

المصدر: بلوق وظيفة تعبير وظيفة استدعاء فورا (iife)

أمثلة بدون قوسين:

void function (msg) { alert(msg); }
('SO');

(هذا هو الاستخدام الحقيقي الوحيد ل Void، AFAIK)

أو

var a = function (msg) { alert(msg); }
('SO');

أو

!function (msg) { alert(msg); }
('SO');

العمل كذلك. ال void يسبب التعبير لتقييم، وكذلك المهمة والانفجار. آخر واحد يعمل مع ~, +, -, delete, typeof, ، بعض المشغلين غير المحللين (void هو واحد كذلك). لا تعمل هي من couse ++, -- بسبب متطلبات المتغير.

استراحة الخط ليست ضرورية.

إنها وظيفة مجهولة بالتنفيذ الذاتي. تحتوي المجموعة الأولى من الأقواس على التعبيرات المراد تنفيذها، وتنفذ المجموعة الثانية من الأقواس هذه التعبيرات.

(function () {
    return ( 10 + 20 );
})();

بيتر Michaux يناقش الفرق في زوج مهم من الأقواس.

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

يرى:

  1. إغلاق (علوم الكمبيوتر)
  2. جافا سكريبت Namespacing.
  3. زوج مهم من قوس جافا سكريبت

وجهة نظر أخرى

أولا، يمكنك إعلان وظيفة مجهولة:

var foo = function(msg){
 alert(msg);
}

ثم تسميها:

foo ('Few');

لأن foo = وظيفة (msg) {elert (msg)؛} لذلك يمكنك استبدال فور كما:

function(msg){
 alert(msg);
} ('Few');

ولكن يجب عليك التفاف وظيفة مجهولة الهوية بالكامل داخل زوج من الأقواس لتجنب خطأ بناء الجملة من وظيفة الإعلان عند التحليل. إذن لدينا،

(function(msg){
 alert(msg);
}) ('Few');

بهذه الطريقة، من السهل فهم لي.

عندما فعلت:

(function (msg){alert(msg)});
('SO');

لقد انتهت الوظيفة من قبل ('SO') بسبب الفاصلة المنقوطة. إذا كتبت فقط:

(function (msg){alert(msg)})
('SO');

سوف تعمل.

مثال العام: http://jsfiddle.net/oliverni/dbvjg/

السبب البسيط لماذا لا يعمل ليس بسبب ; يشير إلى نهاية الوظيفة المجهولة. إنه بسبب () في نهاية مكالمة وظيفة، فإنها ليست مكالمة دالة. إنه،

function help() {return true;}

إذا اتصلت result = help(); هذه مكالمة إلى وظيفة وسوف تعود True.

إذا اتصلت result = help; هذه ليست مكالمة. إنها مهمة يتم فيها التعامل مع التعليمات مثل البيانات المراد تخصيصها.

ما فعلت إعلان / إنشاء وظيفة مجهولة عن طريق إضافة الفاصلة المنقوطة،

(function (msg) { /* Code here */ });

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

('SO');

يرى المترجم الترجم بين الأقواس في السطر الثاني كتعليمات / بيان جديد، وبالتالي فإنه لا يعمل، حتى لو فعلت ذلك مثل هذا:

(function (msg){/*code here*/});('SO');

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

(function (msg){/*code here*/})        // This space is ignored by the interpreter
('SO');

الخلاصة: استدعاء الوظيفة ليست مكالمة دالة بدون () في النهاية، ما لم يكن بموجب شروط محددة مثل التي تم الاحتجاج بها من قبل وظيفة أخرى، فإن Onload = 'Help' ستنفذ وظيفة المساعدة على الرغم من عدم تضمين الأقواس. أعتقد أن settimeout و setinterval تسمح أيضا بنوع الوظيفة دعوة هذا أيضا، وأعتقد أيضا أن المترجم يضيف الأقواس وراء الكواليس على أي حال الذي يعيدنا إلى "مكالمة دالة ليست مكالمة دالة بدون قوسين".

(function (msg){alert(msg)})
('SO');

هذه طريقة شائعة لاستخدام وظيفة مجهولة كإغلاق يستخدم العديد من أطر JavaScript.

يتم استدعاء هذه الوظيفة تلقائيا عند ترجمة التعليمات البرمجية.

إذا وضعت ; في السطر الأول، عامل التحويل البرمجي كخططفين مختلفين. لذلك لا يمكنك الحصول على نفس النتائج على النحو الوارد أعلاه.

هذا يمكن أن يكون مكتوب أيضا على النحو التالي:

(function (msg){alert(msg)}('SO'));

لمزيد من التفاصيل، انظر إلى جافا سكريبت / وظائف مجهولة.

  1. وظائف مجهولة هي وظائف معلنة ديناميكيا في وقت التشغيل. يطلقون عليهم وظائف مجهولة لأنهم لا يعطون اسما بنفس طريقة الوظائف العادية.

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

    إليك مثال نموذجي على وظيفة اسمه:

    وظيفة flytothemoon () {elert ("Zoom! zoom! zoom!")؛ } السفر الى القمر()؛ هنا هو نفس المثال الذي تم إنشاؤه كعامية مجهولة:

    var flytothemoon = وظيفة () {تنبيه ("zoom! zoom! zoom!")؛ } السفر الى القمر()؛

    للحصول على التفاصيل، يرجى قراءة هنا:

    http://helephant.com/2008/08/23/Javascript-anonym-Functions/

iife ببساطة تقسيم الوظيفة ويخفي msg المتغير حتى لا "تلوث" مساحة الاسم العالمية. في الواقع، فقط احتفظ به بسيطة ومثبة أدناه إلا إذا كنت تقوم ببناء موقع مليار دولار.

var msg = "later dude";
window.onunload = function(msg){
  alert( msg );
};

يمكنك مساحة الاسم الخاص بك msg الممتلكات باستخدام أ كشف نمط الوحدة النمطية مثل:

var myScript = (function() {
    var pub = {};
    //myscript.msg
    pub.msg = "later dude";
    window.onunload = function(msg) {
        alert(msg);
    };
    //API
    return pub;
}());

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

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