javascript - لغة - ماهو الجزء المفقود من هذه الدالة؟ function add{var c=a+b; return c;}




var functionName=function(){} مقابل الدالة functionName(){} (20)

أحد الأسباب المهمة هو إضافة متغير واحد فقط باعتباره "الجذر" لمساحة الاسم الخاصة بك ...

var MyNamespace = {}
MyNamespace.foo= function() {

}

أو

var MyNamespace = {
  foo: function() {
  },
  ...
}

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

انظر أيضًا كيف أعلن مساحة الاسم في JavaScript؟

لقد بدأت مؤخرًا في حفظ شفرة جافا سكريبت لشخص آخر. أقوم بإصلاح الأخطاء وإضافة ميزات ومحاولة ترميز التعليمات البرمجية وجعلها أكثر تناسقًا.

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

الطريقتان هي:

var functionOne = function() {
    // Some code
};
function functionTwo() {
    // Some code
}

ما هي أسباب استخدام هاتين الطريقتين المختلفتين وما هي إيجابيات وسلبيات كل منهما؟ هل هناك أي شيء يمكن القيام به بطريقة واحدة لا يمكن القيام بها مع الآخر؟


أريد أولاً تصحيح Greg: يتم تحديد نطاق function abc(){} أيضًا - يتم تعريف اسم abc في النطاق الذي تمت مصادفة هذا التعريف فيه. مثال:

function xyz(){
  function abc(){};
  // abc is defined here...
}
// ...but not here

ثانيًا ، من الممكن الجمع بين كلا النمطين:

var xyz = function abc(){};

xyz سيتم تعريفه كالمعتاد ، abc غير معرفة في كافة المستعرضات ولكن Internet Explorer - لا تعتمد على يتم تعريفها. ولكن سيتم تعريفها داخل جسمها:

var xyz = function abc(){
  // xyz is visible here
  // abc is visible here
}
// xyz is visible here
// abc is undefined here

إذا كنت ترغب في الحصول على وظائف بديلة في جميع المتصفحات ، فاستخدم هذا النوع من الإعلانات:

function abc(){};
var xyz = abc;

في هذه الحالة ، يكون كل من xyz و abc مستعارين للكائن نفسه:

console.log(xyz === abc); // prints "true"

أحد الأسباب المقنعة لاستخدام النمط المدمج هو سمة "name" الخاصة بالكائنات الدالة ( غير مدعمة بواسطة Internet Explorer ). أساسا عند تحديد وظيفة مثل

function abc(){};
console.log(abc.name); // prints "abc"

يتم تعيين اسمها تلقائيا. ولكن عندما تحددها مثل

var abc = function(){};
console.log(abc.name); // prints ""

اسمها فارغ - أنشأنا وظيفة مجهولة وخصصناها لبعض المتغيرات.

ومن الأسباب الجيدة الأخرى لاستخدام النمط المدمج هو استخدام اسم داخلي قصير للإشارة إلى نفسه ، مع توفير اسم طويل غير متعارض للمستخدمين الخارجيين:

// Assume really.long.external.scoped is {}
really.long.external.scoped.name = function shortcut(n){
  // Let it call itself recursively:
  shortcut(n - 1);
  // ...
  // Let it pass itself as a callback:
  someFunction(shortcut);
  // ...
}

في المثال أعلاه يمكننا القيام بنفس الشيء مع اسم خارجي ، ولكنه سيكون غير عملي (وأبطأ).

(هناك طريقة أخرى للإشارة إلى نفسها وهي استخدام arguments.callee ، والتي لا تزال طويلة نسبيًا ، وغير مدعومة في الوضع المقيد.)

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

function abc(){}

يتم تعريف abc هنا في كل مكان في النطاق الحالي:

// We can call it here
abc(); // Works

// Yet, it is defined down there.
function abc(){}

// We can call it again
abc(); // Works

أيضا ، رفعه من خلال بيان return :

// We can call it here
abc(); // Works
return;
function abc(){}

هذا هو تعبير دالة:

var xyz = function(){};

يتم تعريف xyz هنا من نقطة المهمة:

// We can't call it here
xyz(); // UNDEFINED!!!

// Now it is defined
xyz = function(){}

// We can call it here
xyz(); // works

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

حقيقة ممتعة:

var xyz = function abc(){};
console.log(xyz.name); // Prints "abc"

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

var abc = function(){};

أعلم أنني قمت بتعريف الوظيفة محليًا. عندما أقوم بتعريف وظيفة مثل

abc = function(){};

أعرف أني عرّفته عالميًا بشرط أن لا أعرّف أي abc في أي مكان في سلسلة النطاقات. هذا النمط من التعريف مرن حتى عند استخدامه داخل eval() . في حين أن التعريف

function abc(){};

يعتمد على السياق وقد يتركك تخمين حيث تم تعريفه بالفعل ، خاصة في حالة eval() - الإجابة هي: تعتمد على المتصفح.


تتطابق الشفتان التوضيحيتان اللتان قمت بنشرهما فيهما ، تقريبًا مع جميع الأغراض ، بالطريقة نفسها.

ومع ذلك ، فإن الفرق في السلوك هو أنه مع المتغير الأول ( var functionOne = function() {} ) ، لا يمكن استدعاء هذه الدالة إلا بعد تلك النقطة في التعليمة البرمجية.

مع المتغير الثاني ( function functionTwo() ) ، تكون الوظيفة متاحة للتعليمة البرمجية التي يتم تشغيلها أعلى حيث يتم الإعلان عن الوظيفة.

هذا لأنه مع المتغير الأول ، يتم تعيين الدالة للمتغير foo في وقت التشغيل. في الثانية ، يتم تعيين الدالة لهذا المعرّف ، foo ، في وقت التحليل.

مزيد من المعلومات التقنية

تحتوي JavaScript على ثلاث طرق لتعريف الوظائف.

  1. يعرض مقتطفك الأول تعبير دالة . يتضمن ذلك استخدام مشغل "الوظيفة" لإنشاء وظيفة - يمكن تخزين نتيجة المشغل في أي خاصية متغير أو كائن. التعبير الوظيفي قوي بهذه الطريقة. غالباً ما يطلق على تعبير الدوال "وظيفة مجهولة" ، لأنه ليس من الضروري أن يكون له اسم ،
  2. المثال الثاني الخاص بك هو إعلان الدالة . هذا يستخدم العبارة "الدالة" لإنشاء دالة. يتم توفير الوظيفة في وقت التحليل ويمكن استدعاؤها في أي مكان في هذا النطاق. لا يزال بإمكانك تخزينها في خاصية متغير أو كائن في وقت لاحق.
  3. والطريقة الثالثة لتعريف دالة هي مُنشئ "Function ()" ، الذي لا يظهر في مشاركتك الأصلية. من غير المستحسن استخدام هذا لأنه يعمل بنفس طريقة eval() ، التي لديها مشاكلها.

تفسير أفضل لجواب جريج

functionTwo();
function functionTwo() {
}

لماذا لا يوجد خطأ؟ لقد تعلمنا دائما أن يتم تنفيذ تعبيرات من أعلى إلى أسفل (؟؟)

لان:

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

هذا يعني أن الكود مثل هذا:

functionOne();                  ---------------      var functionOne;
                                | is actually |      functionOne();
var functionOne = function(){   | interpreted |-->
};                              |    like     |      functionOne = function(){
                                ---------------      };

لاحظ أن جزء التعيين من الإعلانات لم يتم رفعه. فقط هو رفع الاسم.

ولكن في حالة الإعلانات الدالة ، سيتم رفع هيئة الوظيفة بأكملها أيضًا :

functionTwo();              ---------------      function functionTwo() {
                            | is actually |      };
function functionTwo() {    | interpreted |-->
}                           |    like     |      functionTwo();
                            ---------------

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

أقوم دائمًا ببناء وحدات جافا سكريبت بنمط مثل هذا:

(function(){
    var exports = {};

    function privateUtil() {
            ...
    }

    exports.publicUtil = function() {
            ...
    };

    return exports;
})();

باستخدام هذا النمط ، ستستخدم جميع وظائفك العامة الواجبات ، بينما تستخدم وظائفك الخاصة الإعلان.

(لاحظ أيضًا أن الواجب يجب أن يتطلب فاصلة منقوطة بعد العبارة ، بينما يحظرها الإعلان.)


وهنا المتهدمة على الأشكال القياسية التي تخلق وظائف: (كتبت أصلا لسؤال آخر ، ولكن تكييفها بعد نقلها إلى السؤال الكنسي).

شروط:

القائمة السريعة:

  • إعلان وظيفي

  • function "مجهول" تعبير (على الرغم من وجود المصطلح ، في بعض الأحيان إنشاء دالات بأسماء)

  • مسمى function التعبير

  • إتمام وظيفة ملحق (ES5 +)

  • تعبير دالة السهم (ES2015 +) (والذي ، مثل تعبيرات الدالة المجهولة ، لا يتضمن اسمًا صريحًا ، ومع ذلك يمكنه إنشاء دالات بأسماء)

  • الأسلوب الأسلوب في Initializer كائن (ES2015 +)

  • منشئ ومنشورات الأسلوب في class (ES2015 +)

إعلان وظيفي

النموذج الأول هو إعلان الدالة ، الذي يبدو كالتالي:

function x() {
    console.log('x');
}

الإعلان الوظيفة هو إعلان ؛ انها ليست بيان أو تعبير. على هذا النحو ، فأنت لا تتبعها مع ; (على الرغم من أن ذلك غير ضار).

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

نظرًا لأنه تتم معالجتها قبل أي رمز خطوة بخطوة في السياق نفسه ، يمكنك إجراء أشياء مثل هذه:

x(); // Works even though it's above the declaration
function x() {
    console.log('x');
}

حتى حلول ES2015 ، لم تغطي المواصفات ما يجب أن يفعله محرك جافا سكريبت إذا وضعت إعلانًا وظيفيًا داخل بنية تحكم مثل try ، أو switch ، أو while ، أو ما إلى ذلك ، مثل:

if (someCondition) {
    function foo() {    // <===== HERE THERE
    }                   // <===== BE DRAGONS
}

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

على الرغم من أن هذا لم يتم تحديده حتى ES2015 ، إلا أنه كان امتدادًا مسموحًا به لدعم إعلانات الوظائف في الكتل. للأسف (وحتما) ، فعلت محركات مختلفة أشياء مختلفة.

اعتبارا من ES2015 ، تقول المواصفات ما يجب القيام به. في الواقع ، فإنه يعطي ثلاثة أشياء منفصلة للقيام بها:

  1. إذا لم يكن محرك جافا سكريبت في وضع غير مفعل على متصفح ويب ، فعليه أن يفعل شيئًا واحدًا
  2. إذا كان في وضع غير مستقر على متصفح الويب ، من المفترض مشغل جافا سكريبت أن يفعل شيئا آخر
  3. إذا كان في وضع صارم (المتصفح أم لا) ، من المفترض مشغل جافا سكريبت أن تفعل شيئا آخر

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

"use strict";
if (someCondition) {
    foo();               // Works just fine
    function foo() {
    }
}
console.log(typeof foo); // "undefined" (`foo` is not in scope here
                         // because it's not in the same block)

function "مجهول" التعبير

يسمى النموذج الثاني المشترك تعبير دالة مجهول :

var y = function () {
    console.log('y');
};

مثل جميع التعبيرات ، يتم تقييمها عند الوصول إليها في تنفيذ التعليمات البرمجية خطوة بخطوة.

في ES5 ، لا تحتوي الدالة التي تقوم بإنشائها على اسم (إنه مجهول). في ES2015 ، يتم تعيين اسم الدالة إذا أمكن عن طريق استنتاجه من السياق. في المثال أعلاه ، سيكون الاسم y . يتم تنفيذ شيء مماثل عندما تكون الدالة قيمة مُهيئ الخاصية. (للحصول على تفاصيل حول وقت حدوث ذلك والقواعد ، ابحث عن SetFunctionName في المواصفات - يظهر في كل مكان.)

مسمى function التعبير

النموذج الثالث هو تعبير دالة مسمى ("NFE"):

var z = function w() {
    console.log('zw')
};

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

var z = function w() {
    console.log(typeof w); // "function"
};
console.log(typeof w);     // "undefined"

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

إتمام وظيفة ملحق (ES5 +)

في بعض الأحيان ، يمكن أن تتسلل الوظائف دون أن يلاحظها أحد من قبل ؛ هذا هو الحال مع وظائف ملحق . إليك مثال على ذلك:

var obj = {
    value: 0,
    get f() {
        return this.value;
    },
    set f(v) {
        this.value = v;
    }
};
console.log(obj.f);         // 0
console.log(typeof obj.f);  // "number"

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

يمكنك أيضًا إنشاء وظائف accessor مع Object.defineProperty و Object.defineProperties و الوسيطة الثانية الأقل شهرة إلى Object.create .

تعبير دالة السهم (ES2015 +)

ES2015 يجلب لنا وظيفة السهم . إليك مثال واحد:

var a = [1, 2, 3];
var b = a.map(n => n * 2);
console.log(b.join(", ")); // 2, 4, 6

انظر أن n => n * 2 شيء يختبئ في مكالمة map() ؟ هذه وظيفة

شيئين عن وظائف السهم:

  1. ليس لديهم this خاصة بهم. بدلاً من ذلك ، فإنها تغلق فوق سياق السياق الذي يتم تعريفه فيه. (كما أنها تغلق فوق arguments ، وحيثما يكون ذلك مناسبًا ، super .) وهذا يعني أن this داخلها هو نفس الشيء الذي تم إنشاؤه فيه ، ولا يمكن تغييره.

  2. وكما لاحظت أعلاه ، لا تستخدم function الكلمة الرئيسية ؛ بدلاً من ذلك ، تستخدم => .

المثال n => n * 2 أعلاه هو شكل واحد منها. إذا كان لديك وسائط متعددة لتمرير الوظيفة ، فأنت تستخدم parens:

var a = [1, 2, 3];
var b = a.map((n, i) => n * i);
console.log(b.join(", ")); // 0, 2, 6

(تذكر أن Array#map تمر في الإدخال كالوسيطة الأولى ، والفهرس كالثاني.)

في كلتا الحالتين ، يكون جسم الدالة مجرد تعبير ؛ ستكون قيمة الإرجاع للدالة هي نتيجة هذا التعبير (أنت لا تستخدم إرجاعًا صريحًا).

إذا كنت تفعل أكثر من مجرد تعبير واحد ، فاستخدم {} return صريحًا (إذا كنت تريد إرجاع قيمة) ، كالمعتاد:

var a = [
  {first: "Joe", last: "Bloggs"},
  {first: "Albert", last: "Bloggs"},
  {first: "Mary", last: "Albright"}
];
a = a.sort((a, b) => {
  var rv = a.last.localeCompare(b.last);
  if (rv === 0) {
    rv = a.first.localeCompare(b.first);
  }
  return rv;
});
console.log(JSON.stringify(a));

يسمى الإصدار بدون { ... } دالة سهم مع نص تعبير أو نص موجزة . (أيضا: وظيفة سهم موجزة .) واحد مع { ... } تعريف الجسم هو وظيفة السهم مع هيئة وظيفة . (أيضا: وظيفة السهم المطول .)

الأسلوب الأسلوب في Initializer كائن (ES2015 +)

يسمح ES2015 بنمط أقصر للإعلان عن خاصية تشير إلى وظيفة ؛ تبدو هكذا:

var o = {
    foo() {
    }
};

المكافئ في ES5 وما قبله سيكون:

var o = {
    foo: function foo() {
    }
};

منشئ ومنشورات الأسلوب في class (ES2015 +)

ES2015 يجلب لنا بناء الجملة ، بما في ذلك المنشئات والأساليب المعلنة:

class Person {
    constructor(firstName, lastName) {
        this.firstName = firstName;
        this.lastName = lastName;
    }

    getFullName() {
        return this.firstName + " " + this.lastName;
    }
}

هناك نوعان من إعلانات الدالة أعلاه: واحد منشئ ، والذي يحصل على اسم Person ، وواحد لـ getFullName ، وهي دالة تم تعيينها إلى Person.prototype .


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

مع

if (condition){
    function myfunction(){
        // Some code
    }
}

، هذا التعريف ل myfunction سوف يتجاوز أي تعريف سابق ، لأنه سيتم في وقت التحليل.

في حين

if (condition){
    var myfunction = function (){
        // Some code
    }
}

يقوم بالمهمة الصحيحة لتحديد وظيفة فقط عندما يتم استيفاء condition .


new Function()يمكن استخدامها لتمرير جسم الدالة في سلسلة. وبالتالي يمكن استخدام هذا لإنشاء وظائف ديناميكية. أيضا تمرير البرنامج النصي دون تنفيذ البرنامج النصي.

var func = new Function("x", "y", "return x*y;");
function secondFunction(){
   var result;
   result = func(10,20);
   console.log ( result );
}

secondFunction()

حول الأداء:

V8قدمت إصدارات جديدة من العديد من التحسينات تحت غطاء محرك السيارة وكذلك فعلت SpiderMonkey.

لا يوجد فرق تقريبا الآن بين التعبير والإعلان. يبدو
تعبير الدالة أسرع الآن.

Chrome 62.0.3202

FireFox 55

الكروم الكناري 63.0.3225


Anonymousيبدو أن تعبيرات الدالة لها أداء أفضل ضد Namedتعبير الدالة.


فايرفوكس كروم كناري كروم


أدرج الاختلافات أدناه:

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

    ألق نظرة على الوظيفة أدناه:

    function outerFunction() {
        function foo() {
           return 1;
        }
        return foo();
        function foo() {
           return 2;
        }
    }
    alert(outerFunction()); // Displays 2
    

    هذا لأنه ، أثناء التنفيذ ، يبدو مثل: -

    function foo() {  // The first function declaration is moved to top
        return 1;
    }
    function foo() {  // The second function declaration is moved to top
        return 2;
    }
    function outerFunction() {
        return foo();
    }
    alert(outerFunction()); //So executing from top to bottom,
                            //the last foo() returns 2 which gets displayed
    

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

    نفس الوظيفة باستخدام تعبيرات الدالة:

    function outerFunction() {
        var foo = function() {
           return 1;
        }
        return foo();
        var foo = function() {
           return 2;
        }
    }
    alert(outerFunction()); // Displays 1
    

    هذا لأنه أثناء التنفيذ ، يبدو كالتالي:

    function outerFunction() {
       var foo = undefined;
       var foo = undefined;
    
       foo = function() {
          return 1;
       };
       return foo ();
       foo = function() {   // This function expression is not reachable
          return 2;
       };
    }
    alert(outerFunction()); // Displays 1
    
  2. ليس من الآمن كتابة إعلانات الدالة في كتل غير وظيفية كما لو كان ذلك بسبب عدم إمكانية الوصول إليها.

    if (test) {
        function x() { doSomething(); }
    }
    
  3. قد لا يعمل تعبير الدالة المسماة مثل التعبير الموضح أدناه ، في مستعرضات Internet Explorer قبل الإصدار 9.

    var today = function today() {return new Date()}
    

أقوم بإضافة إجابتي الخاصة فقط لأن كل شخص آخر قام بتغطية جزء الرفع بشكل كامل.

لقد تساءلت عن الطريقة الأفضل لفترة طويلة الآن ، وبفضل http://jsperf.com الآن أعرف :)

إعلانات الوظائف أسرع ، وهذا ما يهم حقًا في مطوري الويب؟ ؛)


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

التعبير الوظيفي:

var foo = function foo() {};

بيان الوظيفة:

function foo() {};

بيان الدالة هو مجرد اختصار لعبارة varذات functionقيمة.

وبالتالي

function foo() {};

يتوسع ل

var foo = function foo() {};

الذي يتوسع كذلك إلى:

var foo = undefined;
foo = function foo() {};

وكلاهما يرفعان إلى أعلى الشفرة.


اختلاف آخر غير مذكور في الإجابات الأخرى هو أنه إذا كنت تستخدم الدالة المجهولة

var functionOne = function() {
    // Some code
};

واستخدام ذلك كمنشئ كما في

var one = new functionOne();

ثم one.constructor.nameلن يتم تعريفها. Function.nameغير قياسي ولكن مدعوم من قِبل Firefox و Chrome والمتصفحات الأخرى المشتقة من Webkit و IE 9+.

مع

function functionTwo() {
    // Some code
}
two = new functionTwo();

من الممكن استرداد اسم المنشئ كسلسلة مع two.constructor.name.


المثال الأول هو إعلان الدالة:

function abc(){}

المثال الثاني هو تعبير دالة:

var abc = function() {};

الفرق الرئيسي هو كيف يتم رفع (رفع وإعلان). في المثال الأول ، يتم رفع إعلان الدالة بالكامل. في المثال الثاني يتم رفع var 'abc' فقط ، ولن يتم تحديد قيمته (الوظيفة) ، وتظل الوظيفة نفسها في الموضع الذي يتم الإعلان عنه.

بكل بساطة:

//this will work
abc(param);
function abc(){}

//this would fail
abc(param);
var abc = function() {}

لدراسة المزيد حول هذا الموضوع ، أوصيك بشدة بهذا link


في JavaScript هناك طريقتان لإنشاء الدالات:

  1. بيان الوظيفة:

    function fn(){
      console.log("Hello");
    }
    fn();
    

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

    ما يجب أن تعرفه هو أن الوظائف في الواقع كائنات في JavaScript. داخليا قمنا بإنشاء كائن للوظيفة أعلاه وأعطناه اسم يسمى fn أو يتم تخزين الإشارة إلى الكائن في fn. وظائف هي كائنات في جافا سكريبت. مثيل وظيفة هو في الواقع مثيل كائن.

  2. التعبير الوظيفي:

    var fn=function(){
      console.log("Hello");
    }
    fn();
    

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

المرجع: صيغة تعريف دالة JavaScript: var fn = function () {} مقابل الدالة fn () {}


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

حتى كتابة هذه السطور ، يشير V8 و SpiderMonkey و Chakra و Nitro دائماً إلى الوظائف المسماة بأسمائهم. هم دائما تقريبا تشير إلى وظيفة مجهولة من خلال معرفه إذا كان لديه واحد.

يمكن لـ SpiderMonkey معرفة اسم دالة مجهولة تم إرجاعها من دالة أخرى. الباقي لا يستطيع.

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

[].forEach(function iterator() {});

ولكن بالنسبة للجزء الأكبر لا يستحق التأكيد على.

تسخير ( Fiddle )

'use strict';

var a = function () {
    throw new Error();
},
    b = function b() {
        throw new Error();
    },
    c = function d() {
        throw new Error();
    },
    e = {
        f: a,
        g: b,
        h: c,
        i: function () {
            throw new Error();
        },
        j: function j() {
            throw new Error();
        },
        k: function l() {
            throw new Error();
        }
    },
    m = (function () {
        return function () {
            throw new Error();
        };
    }()),
    n = (function () {
        return function n() {
            throw new Error();
        };
    }()),
    o = (function () {
        return function p() {
            throw new Error();
        };
    }());

console.log([a, b, c].concat(Object.keys(e).reduce(function (values, key) {
    return values.concat(e[key]);
}, [])).concat([m, n, o]).reduce(function (logs, func) {

    try {
        func();
    } catch (error) {
        return logs.concat('func.name: ' + func.name + '\n' +
                           'Trace:\n' +
                           error.stack);
        // Need to manually log the error object in Nitro.
    }

}, []).join('\n\n'));

V8

func.name: 
Trace:
Error
    at a (http://localhost:8000/test.js:4:11)
    at http://localhost:8000/test.js:47:9
    at Array.reduce (native)
    at http://localhost:8000/test.js:44:27

func.name: b
Trace:
Error
    at b (http://localhost:8000/test.js:7:15)
    at http://localhost:8000/test.js:47:9
    at Array.reduce (native)
    at http://localhost:8000/test.js:44:27

func.name: d
Trace:
Error
    at d (http://localhost:8000/test.js:10:15)
    at http://localhost:8000/test.js:47:9
    at Array.reduce (native)
    at http://localhost:8000/test.js:44:27

func.name: 
Trace:
Error
    at a (http://localhost:8000/test.js:4:11)
    at http://localhost:8000/test.js:47:9
    at Array.reduce (native)
    at http://localhost:8000/test.js:44:27

func.name: b
Trace:
Error
    at b (http://localhost:8000/test.js:7:15)
    at http://localhost:8000/test.js:47:9
    at Array.reduce (native)
    at http://localhost:8000/test.js:44:27

func.name: d
Trace:
Error
    at d (http://localhost:8000/test.js:10:15)
    at http://localhost:8000/test.js:47:9
    at Array.reduce (native)
    at http://localhost:8000/test.js:44:27

func.name: 
Trace:
Error
    at e.i (http://localhost:8000/test.js:17:19)
    at http://localhost:8000/test.js:47:9
    at Array.reduce (native)
    at http://localhost:8000/test.js:44:27

func.name: j
Trace:
Error
    at j (http://localhost:8000/test.js:20:19)
    at http://localhost:8000/test.js:47:9
    at Array.reduce (native)
    at http://localhost:8000/test.js:44:27

func.name: l
Trace:
Error
    at l (http://localhost:8000/test.js:23:19)
    at http://localhost:8000/test.js:47:9
    at Array.reduce (native)
    at http://localhost:8000/test.js:44:27

func.name: 
Trace:
Error
    at http://localhost:8000/test.js:28:19
    at http://localhost:8000/test.js:47:9
    at Array.reduce (native)
    at http://localhost:8000/test.js:44:27

func.name: n
Trace:
Error
    at n (http://localhost:8000/test.js:33:19)
    at http://localhost:8000/test.js:47:9
    at Array.reduce (native)
    at http://localhost:8000/test.js:44:27

func.name: p
Trace:
Error
    at p (http://localhost:8000/test.js:38:19)
    at http://localhost:8000/test.js:47:9
    at Array.reduce (native)
    at http://localhost:8000/test.js:44:27 test.js:42

القرد العنكبوت

func.name: 
Trace:
[email protected]://localhost:8000/test.js:4:5
@http://localhost:8000/test.js:47:9
@http://localhost:8000/test.js:54:1


func.name: b
Trace:
[email protected]://localhost:8000/test.js:7:9
@http://localhost:8000/test.js:47:9
@http://localhost:8000/test.js:54:1


func.name: d
Trace:
[email protected]://localhost:8000/test.js:10:9
@http://localhost:8000/test.js:47:9
@http://localhost:8000/test.js:54:1


func.name: 
Trace:
[email protected]://localhost:8000/test.js:4:5
@http://localhost:8000/test.js:47:9
@http://localhost:8000/test.js:54:1


func.name: b
Trace:
[email protected]://localhost:8000/test.js:7:9
@http://localhost:8000/test.js:47:9
@http://localhost:8000/test.js:54:1


func.name: d
Trace:
[email protected]://localhost:8000/test.js:10:9
@http://localhost:8000/test.js:47:9
@http://localhost:8000/test.js:54:1


func.name: 
Trace:
[email protected]://localhost:8000/test.js:17:13
@http://localhost:8000/test.js:47:9
@http://localhost:8000/test.js:54:1


func.name: j
Trace:
[email protected]://localhost:8000/test.js:20:13
@http://localhost:8000/test.js:47:9
@http://localhost:8000/test.js:54:1


func.name: l
Trace:
[email protected]://localhost:8000/test.js:23:13
@http://localhost:8000/test.js:47:9
@http://localhost:8000/test.js:54:1


func.name: 
Trace:
m</<@http://localhost:8000/test.js:28:13
@http://localhost:8000/test.js:47:9
@http://localhost:8000/test.js:54:1


func.name: n
Trace:
[email protected]://localhost:8000/test.js:33:13
@http://localhost:8000/test.js:47:9
@http://localhost:8000/test.js:54:1


func.name: p
Trace:
[email protected]://localhost:8000/test.js:38:13
@http://localhost:8000/test.js:47:9
@http://localhost:8000/test.js:54:1

شقرا

func.name: undefined
Trace:
Error
   at a (http://localhost:8000/test.js:4:5)
   at Anonymous function (http://localhost:8000/test.js:47:9)
   at Global code (http://localhost:8000/test.js:42:1)


func.name: undefined
Trace:
Error
   at b (http://localhost:8000/test.js:7:9)
   at Anonymous function (http://localhost:8000/test.js:47:9)
   at Global code (http://localhost:8000/test.js:42:1)


func.name: undefined
Trace:
Error
   at d (http://localhost:8000/test.js:10:9)
   at Anonymous function (http://localhost:8000/test.js:47:9)
   at Global code (http://localhost:8000/test.js:42:1)


func.name: undefined
Trace:
Error
   at a (http://localhost:8000/test.js:4:5)
   at Anonymous function (http://localhost:8000/test.js:47:9)
   at Global code (http://localhost:8000/test.js:42:1)


func.name: undefined
Trace:
Error
   at b (http://localhost:8000/test.js:7:9)
   at Anonymous function (http://localhost:8000/test.js:47:9)
   at Global code (http://localhost:8000/test.js:42:1)


func.name: undefined
Trace:
Error
   at d (http://localhost:8000/test.js:10:9)
   at Anonymous function (http://localhost:8000/test.js:47:9)
   at Global code (http://localhost:8000/test.js:42:1)


func.name: undefined
Trace:
Error
   at e.i (http://localhost:8000/test.js:17:13)
   at Anonymous function (http://localhost:8000/test.js:47:9)
   at Global code (http://localhost:8000/test.js:42:1)


func.name: undefined
Trace:
Error
   at j (http://localhost:8000/test.js:20:13)
   at Anonymous function (http://localhost:8000/test.js:47:9)
   at Global code (http://localhost:8000/test.js:42:1)


func.name: undefined
Trace:
Error
   at l (http://localhost:8000/test.js:23:13)
   at Anonymous function (http://localhost:8000/test.js:47:9)
   at Global code (http://localhost:8000/test.js:42:1)


func.name: undefined
Trace:
Error
   at Anonymous function (http://localhost:8000/test.js:28:13)
   at Anonymous function (http://localhost:8000/test.js:47:9)
   at Global code (http://localhost:8000/test.js:42:1)


func.name: undefined
Trace:
Error
   at n (http://localhost:8000/test.js:33:13)
   at Anonymous function (http://localhost:8000/test.js:47:9)
   at Global code (http://localhost:8000/test.js:42:1)


func.name: undefined
Trace:
Error
   at p (http://localhost:8000/test.js:38:13)
   at Anonymous function (http://localhost:8000/test.js:47:9)
   at Global code (http://localhost:8000/test.js:42:1)

نيترو

func.name: 
Trace:
[email protected]://localhost:8000/test.js:4:22
http://localhost:8000/test.js:47:13
[email protected][native code]
global [email protected]://localhost:8000/test.js:44:33

func.name: b
Trace:
[email protected]://localhost:8000/test.js:7:26
http://localhost:8000/test.js:47:13
[email protected][native code]
global [email protected]://localhost:8000/test.js:44:33

func.name: d
Trace:
[email protected]://localhost:8000/test.js:10:26
http://localhost:8000/test.js:47:13
[email protected][native code]
global [email protected]://localhost:8000/test.js:44:33

func.name: 
Trace:
[email protected]://localhost:8000/test.js:4:22
http://localhost:8000/test.js:47:13
[email protected][native code]
global [email protected]://localhost:8000/test.js:44:33

func.name: b
Trace:
[email protected]://localhost:8000/test.js:7:26
http://localhost:8000/test.js:47:13
[email protected][native code]
global [email protected]://localhost:8000/test.js:44:33

func.name: d
Trace:
[email protected]://localhost:8000/test.js:10:26
http://localhost:8000/test.js:47:13
[email protected][native code]
global [email protected]://localhost:8000/test.js:44:33

func.name: 
Trace:
[email protected]://localhost:8000/test.js:17:30
http://localhost:8000/test.js:47:13
[email protected][native code]
global [email protected]://localhost:8000/test.js:44:33

func.name: j
Trace:
[email protected]://localhost:8000/test.js:20:30
http://localhost:8000/test.js:47:13
[email protected][native code]
global [email protected]://localhost:8000/test.js:44:33

func.name: l
Trace:
[email protected]://localhost:8000/test.js:23:30
http://localhost:8000/test.js:47:13
[email protected][native code]
global [email protected]://localhost:8000/test.js:44:33

func.name: 
Trace:
http://localhost:8000/test.js:28:30
http://localhost:8000/test.js:47:13
[email protected][native code]
global [email protected]://localhost:8000/test.js:44:33

func.name: n
Trace:
[email protected]://localhost:8000/test.js:33:30
http://localhost:8000/test.js:47:13
[email protected][native code]
global [email protected]://localhost:8000/test.js:44:33

func.name: p
Trace:
[email protected]://localhost:8000/test.js:38:30
http://localhost:8000/test.js:47:13
[email protected][native code]
global [email protected]://localhost:8000/test.js:44:33

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


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

  1. توافر (نطاق) للوظيفة

الأعمال التالية لأنه function add()تم تحديد نطاقه لأقرب كتلة:

try {
  console.log("Success: ", add(1, 1));
} catch(e) {
  console.log("ERROR: " + e);
}

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

ما يلي لا يعمل (لأن var add=superseeds function add()).

try {
  console.log("Success: ", add(1, 1));
} catch(e) {
  console.log("ERROR: " + e);
}

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

لا يعمل التالي لأنه addيتم التصريح بعد استخدامه.

try {
  console.log("Success: ", add(1, 1));
} catch(e) {
  console.log("ERROR: " + e);
}

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

  1. (وظيفة) .name

اسم الدالة function thefuncname(){}هو اسم العلامة عند الإعلان عنها بهذه الطريقة.

function foobar(a, b){}

console.log(foobar.name);

var a = function foobar(){};

console.log(a.name);

خلاف ذلك ، إذا تم الإعلان عن وظيفة كدالةfunction(){} ، فإن الدالة .name هو أول متغير يستخدم لتخزين الوظيفة.

var a = function(){};
var b = (function(){ return function(){} });

console.log(a.name);
console.log(b.name);

إذا لم تكن هناك متغيرات مضبوطة على الدالة ، فسيكون اسم الدالات هو السلسلة الفارغة ( "").

console.log((function(){}).name === "");

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

var a = function(){};
var b = a;
var c = b;

console.log(a.name);
console.log(b.name);
console.log(c.name);

  1. أداء

في V8 من Google و Spidermonkey في فايرفوكس قد يكون هناك عدد قليل من اختلافات تجميع JIST microsecond ، ولكن في النهاية تكون النتيجة هي نفسها. لإثبات ذلك ، دعنا نفحص كفاءة JSPerf في microbenchmarks بمقارنة سرعة مقتطفين رمز فارغين. و توجد اختبارات JSPerf هنا . ووجدت jsben.ch testsare هنا . كما ترون ، هناك فرق ملحوظ عندما لا يكون هناك شيء. إذا كنت حقاً مثابراً للأداء مثلي ، فقد يكون الأمر أكثر قيمة بالنسبة لك أثناء محاولة تقليل عدد المتغيرات والوظائف في النطاق وخاصة القضاء على تعدد الأشكال (مثل استخدام المتغير نفسه لتخزين نوعين مختلفين).

ما هو "أقرب كتلة"

"أقرب كتلة" هي أقرب "وظيفة" (بما في ذلك الوظائف غير المتزامنة ، وظائف المولد ، وظائف المولد غير المتزامن). ومع ذلك ، من المثير للاهتمام ، أن function functionName() {}تتصرف مثل var functionName = function() {}عندما في كتلة غير إغلاق إلى عناصر خارج إغلاق قال. رصد.

  • عادي var add=function(){}

try {
  // typeof will simply return "undefined" if the variable does not exist
  if (typeof add !== "undefined") {
    add(1, 1); // just to prove it
    console.log("Not a block");
  }else if(add===undefined){ // this throws an exception if add doesn't exist
    console.log('Behaves like var add=function(a,b){return a+b}');
  }
} catch(e) {
  console.log("Is a block");
}
var add=function(a, b){return a + b}

  • عادي function add(){}

try {
  // typeof will simply return "undefined" if the variable does not exist
  if (typeof add !== "undefined") {
    add(1, 1); // just to prove it
    console.log("Not a block");
  }else if(add===undefined){ // this throws an exception if add doesn't exist
    console.log('Behaves like var add=function(a,b){return a+b}')
  }
} catch(e) {
  console.log("Is a block");
}
function add(a, b){
  return a + b;
}

  • وظيفة

try {
  // typeof will simply return "undefined" if the variable does not exist
  if (typeof add !== "undefined") {
    add(1, 1); // just to prove it
    console.log("Not a block");
  }else if(add===undefined){ // this throws an exception if add doesn't exist
    console.log('Behaves like var add=function(a,b){return a+b}')
  }
} catch(e) {
  console.log("Is a block");
}
(function () {
    function add(a, b){
      return a + b;
    }
})();

  • البيان (مثل if، else، for، while، try/ catch/ finally، switch، do/ while، with)

try {
  // typeof will simply return "undefined" if the variable does not exist
  if (typeof add !== "undefined") {
    add(1, 1); // just to prove it
    console.log("Not a block");
  }else if(add===undefined){ // this throws an exception if add doesn't exist
    console.log('Behaves like var add=function(a,b){return a+b}')
  }
} catch(e) {
  console.log("Is a block");
}
{
    function add(a, b){
      return a + b;
    }
}

  • السهم مع وظيفة var add=function()

try {
  // typeof will simply return "undefined" if the variable does not exist
  if (typeof add !== "undefined") {
    add(1, 1); // just to prove it
    console.log("Not a block");
  }else if(add===undefined){ // this throws an exception if add doesn't exist
    console.log('Behaves like var add=function(a,b){return a+b}')
  }
} catch(e) {
  console.log("Is a block");
}
(() => {
    var add=function(a, b){
      return a + b;
    }
})();

  • السهم مع وظيفة function add()

try {
  // typeof will simply return "undefined" if the variable does not exist
  if (typeof add !== "undefined") {
    add(1, 1); // just to prove it
    console.log("Not a block");
  }else if(add===undefined){ // this throws an exception if add doesn't exist
    console.log('Behaves like var add=function(a,b){return a+b}')
  }
} catch(e) {
  console.log("Is a block");
}
(() => {
    function add(a, b){
      return a + b;
    }
})();


يجب أن يكون الأول (الدالة doSomething (x)) جزءًا من تدوين كائن.

الثاني ( var doSomething = function(x){ alert(x);}) هو ببساطة خلق وظيفة مجهولة وتعيينها لمتغير doSomething،. لذا ستقوم الدالة () باستدعاء الوظيفة.

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

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

function foo() {
    return 3;
}

يعرّف ECMA 5 (13.0) بناء الجملة
كمعرّف الدالة (FormalParameterList opt ) {FunctionBody}

في الحالة أعلاه ، يكون اسم الدالة مرئيًا في نطاقه ونطاقه الرئيسي (وإلا لن يكون قابلاً للوصول إليه).

وفي تعبير وظيفة

يقوم تعبير الدالة بتعريف وظيفة كجزء من بنية تعبير أكبر (عادةً ما يكون تعيين متغير). يمكن تسمية الدوال التي يتم تعريفها عبر تعبيرات الدوال أو المجهول. يجب ألا تبدأ تعبيرات الدالة بـ "الوظيفة".

// Anonymous function expression
var a = function() {
    return 3;
}

// Named function expression
var a = function foo() {
    return 3;
}

// Self-invoking function expression
(function foo() {
    alert("hello!");
})();

يعرّف ECMA 5 (13.0) بناء الجملة على أنه
الوظيفة Identifier opt (FormalParameterList opt ) {FunctionBody}


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

لمزيد من المعلومات حول الوظائف المجهولة و lambda calculus ، تعد Wikipedia بداية جيدة ( http://en.wikipedia.org/wiki/Anonymous_function ).







idioms