وظيفة الحمولة الزائدة في جافا سكريبت - أفضل الممارسات

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

  •  19-08-2019
  •  | 
  •  

سؤال

ما هي أفضل طريقة(s) إلى وظيفة وهمية الحمولة الزائدة في جافا سكريبت ؟

وأنا أعلم أنه لا يمكن أن تفرط في وظائف جافا سكريبت كما في اللغات الأخرى.إذا كنت بحاجة إلى وظيفة مع اثنين من الاستخدامات foo(x) و foo(x,y,z) الذي هو أفضل / يفضل الطريقة:

  1. باستخدام أسماء مختلفة في المقام الأول
  2. استخدام وسيطات اختيارية مثل y = y || 'default'
  3. باستخدام عدد من الحجج
  4. التحقق من أنواع الحجج
  5. أو كيف ؟
هل كانت مفيدة؟

المحلول

أفضل طريقة للقيام وظيفة الحمولة الزائدة مع المعايير لا تحقق حجة طول أو أنواع ؛ التحقق من أنواع سيجعل الكود الخاص بك بطيئة لديك متعة صفائف من القيم الخالية, الأجسام, الخ.

ما معظم المطورين هل هو تك على كائن آخر حجة على أساليبهم.هذا الكائن يمكن أن تعقد أي شيء.

function foo(a, b, opts) {
  // ...
  if (opts['test']) { } //if test param exists, do something.. 
}


foo(1, 2, {"method":"add"});
foo(3, 4, {"test":"equals", "bar":"tree"});

ثم يمكنك التعامل معها على أي حال كنت ترغب في الأسلوب الخاص بك.[التبديل ، إذا غيرك ، وما إلى ذلك.]

نصائح أخرى

أنا في كثير من الأحيان القيام بذلك:

C#:

public string CatStrings(string p1)                  {return p1;}
public string CatStrings(string p1, int p2)          {return p1+p2.ToString();}
public string CatStrings(string p1, int p2, bool p3) {return p1+p2.ToString()+p3.ToString();}

CatStrings("one");        // result = one
CatStrings("one",2);      // result = one2
CatStrings("one",2,true); // result = one2true

جافا سكريبت ما يعادلها:

function CatStrings(p1, p2, p3)
{
  var s = p1;
  if(typeof p2 !== "undefined") {s += p2;}
  if(typeof p3 !== "undefined") {s += p3;}
  return s;
};

CatStrings("one");        // result = one
CatStrings("one",2);      // result = one2
CatStrings("one",2,true); // result = one2true

هذا المثال هو في الواقع أكثر أناقة في جافا سكريبت من C#.المعلمات التي لم يتم تحديدها هي 'undefined' في جافا سكريبت ، والتي يتم تقييمها إلى false في جملة if.ومع ذلك ، فإن تعريف الدالة لا ينقل المعلومات التي p2 و p3 اختيارية.إذا كنت في حاجة الى الكثير من الحمولة الزائدة, مسج قررت استخدام كائن كما المعلمة, على سبيل المثال, مسج.اياكس(خيارات).وأنا أتفق معهم في أن هذا هو أقوى بوضوح متدبرة نهج الحمولة الزائدة ، ولكن نادرا ما تحتاج إلى أكثر من واحد أو اثنين سريعة المعلمات الاختيارية.

تحرير:تغير إذا كان الاختبار في إيان اقتراح

لا يوجد وظيفة حقيقية الحمولة الزائدة في جافا سكريبت لأنه يسمح لتمرير أي عدد من المعلمات من أي نوع.لديك للتحقق من داخل الدالة كم الحجج وقد مرت و ما هو نوع هم.

الجواب الصحيح هو عدم وجود الحمولة الزائدة في جافا سكريبت.

التحقق / التبديل داخل الدالة ليست الحمولة الزائدة.

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

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

https://en.wikipedia.org/wiki/Function_overloading

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

هناك طريقتان يمكنك أن هذا النهج أفضل:

  1. تمر القاموس (النقابي) إذا كنت تريد أن تترك الكثير من المرونة

  2. اتخاذ كائن مثل حجة و استخدام النموذج على أساس الميراث إضافة المرونة.

هنا هو النهج الذي يسمح الحقيقي طريقة التحميل الزائد باستخدام المعلمة أنواع ، كما هو موضح أدناه:

Func(new Point());
Func(new Dimension());
Func(new Dimension(), new Point());
Func(0, 0, 0, 0);

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

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


هنا هو المعيار من نهج مختلفة - https://jsperf.com/function-overloading.فإنه يدل على أن وظيفة الحمولة الزائدة (مع أنواع بعين الاعتبار) يمكن أن يكون حول 13 مرات أبطأ في جوجل كروم V8 اعتبارا من 16.0(بيتا).

فضلا عن تمرير كائن (أي {x: 0, y: 0}) يمكن أيضا أن تأخذ C النهج عند الاقتضاء ، تسمية الطرق تبعا لذلك.على سبيل المثال ناقلات.AddVector(ناقلات), ناقلات.AddIntegers(x, y, z, ...) و ناقلات.AddArray(integerArray).يمكنك أن تبحث في ج المكتبات مثل OpenGL لتسمية الإلهام.

تحرير:لقد أضاف معيارا تمرير كائن اختبار الكائن باستخدام كل 'param' in arg و arg.hasOwnProperty('param'), و وظيفة الحمولة الزائدة هي أسرع بكثير من تمرير كائن والتحقق من خصائص (في هذا المعيار على الأقل).

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

بلدي على سبيل المثال يأتي من مستطيل التنفيذ ومن ثم ذكر بعد نقطة.ربما مستطيل يمكن إضافة GetRectangle() طريقة Dimension و Point النموذج ثم وظيفة إثقال المسألة يتم فرز.و ماذا عن الأوليات?حسنا, لدينا حجة طول, الذي هو الآن اختبار صالح منذ الكائنات لديها GetRectangle() الأسلوب.

function Dimension() {}
function Point() {}

var Util = {};

Util.Redirect = function (args, func) {
  'use strict';
  var REDIRECT_ARGUMENT_COUNT = 2;

  if(arguments.length - REDIRECT_ARGUMENT_COUNT !== args.length) {
    return null;
  }

  for(var i = REDIRECT_ARGUMENT_COUNT; i < arguments.length; ++i) {
    var argsIndex = i-REDIRECT_ARGUMENT_COUNT;
    var currentArgument = args[argsIndex];
    var currentType = arguments[i];
    if(typeof(currentType) === 'object') {
      currentType = currentType.constructor;
    }
    if(typeof(currentType) === 'number') {
      currentType = 'number';
    }
    if(typeof(currentType) === 'string' && currentType === '') {
      currentType = 'string';
    }
    if(typeof(currentType) === 'function') {
      if(!(currentArgument instanceof currentType)) {
        return null;
      }
    } else {
      if(typeof(currentArgument) !== currentType) {
        return null;
      }
    } 
  }
  return [func.apply(this, args)];
}

function FuncPoint(point) {}
function FuncDimension(dimension) {}
function FuncDimensionPoint(dimension, point) {}
function FuncXYWidthHeight(x, y, width, height) { }

function Func() {
  Util.Redirect(arguments, FuncPoint, Point);
  Util.Redirect(arguments, FuncDimension, Dimension);
  Util.Redirect(arguments, FuncDimensionPoint, Dimension, Point);
  Util.Redirect(arguments, FuncXYWidthHeight, 0, 0, 0, 0);
}

Func(new Point());
Func(new Dimension());
Func(new Dimension(), new Point());
Func(0, 0, 0, 0);

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

  1. استخدام وسيطات اختيارية مثل y = y || 'الافتراضي'. هذا هو مريحة إذا كنت تستطيع أن تفعل ذلك, ولكن قد لا تعمل دائما من الناحية العملية ، على سبيل المثالعندما 0/null/غير معروف سيكون حجة صحيحة.

  2. باستخدام عدد من الحجج. على غرار الخيار الأخير ولكن قد تعمل عند رقم 1 لا يعمل.

  3. التحقق من أنواع الحجج. هذا يمكن أن تعمل في بعض الحالات التي يكون فيها عدد من الحجج هو نفسه.إذا كنت لا يمكن تحديد موثوق أنواع, قد تحتاج إلى استخدام أسماء مختلفة.

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

إذا كنت بحاجة إلى وظيفة مع اثنين من الاستخدامات فو(x) فو(x,y,z) الذي هو أفضل / يفضل الطريقة ؟

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

واحد من الطريق أعتقد هو مناسبة لمعظم القضية على النحو التالي -

دعونا نقول لديك طريقة

function foo(x)
{
} 

بدلا من إثقال طريقة وهو أمر غير ممكن في جافا سكريبت يمكنك تحديد طريقة جديدة

fooNew(x,y,z)
{
}

ثم قم بتعديل 1 وظيفة على النحو التالي -

function foo(arguments)
{
  if(arguments.length==2)
  {
     return fooNew(arguments[0],  arguments[1]);
  }
} 

إذا كان لديك العديد من هذه طاقتها أساليب النظر في استخدام switch من if-else التصريحات.

(المزيد من التفاصيل)

PS:الرابط أعلاه يذهب إلى بلدي بلوق الشخصية أن لديها تفاصيل إضافية.

أنا غير متأكد حول أفضل الممارسات ، ولكن هنا هو كيف نفعل ذلك:

/*
 * Object Constructor
 */
var foo = function(x) {
    this.x = x;
};

/*
 * Object Protoype
 */
foo.prototype = {
    /*
     * f is the name that is going to be used to call the various overloaded versions
     */
    f: function() {

        /*
         * Save 'this' in order to use it inside the overloaded functions
         * because there 'this' has a different meaning.
         */   
        var that = this;  

        /* 
         * Define three overloaded functions
         */
        var f1 = function(arg1) {
            console.log("f1 called with " + arg1);
            return arg1 + that.x;
        }

        var f2 = function(arg1, arg2) {
             console.log("f2 called with " + arg1 + " and " + arg2);
             return arg1 + arg2 + that.x;
        }

        var f3 = function(arg1) {
             console.log("f3 called with [" + arg1[0] + ", " + arg1[1] + "]");
             return arg1[0] + arg1[1];
        }

        /*
         * Use the arguments array-like object to decide which function to execute when calling f(...)
         */
        if (arguments.length === 1 && !Array.isArray(arguments[0])) {
            return f1(arguments[0]);
        } else if (arguments.length === 2) {
            return f2(arguments[0], arguments[1]);
        } else if (arguments.length === 1 && Array.isArray(arguments[0])) {
            return f3(arguments[0]);
        }
    } 
}

/* 
 * Instantiate an object
 */
var obj = new foo("z");

/*
 * Call the overloaded functions using f(...)
 */
console.log(obj.f("x"));         // executes f1, returns "xz"
console.log(obj.f("x", "y"));    // executes f2, returns "xyz"
console.log(obj.f(["x", "y"]));  // executes f3, returns "xy"

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

TEST = {};

TEST.multiFn = function(){
    // function map for our overloads
    var fnMap = {};

    fnMap[0] = function(){
        console.log("nothing here");
        return this;    //    support chaining
    }

    fnMap[1] = function(arg1){
        //    CODE here...
        console.log("1 arg: "+arg1);
        return this;
    };

    fnMap[2] = function(arg1, arg2){
        //    CODE here...
        console.log("2 args: "+arg1+", "+arg2);
        return this;
    };

    fnMap[3] = function(arg1,arg2,arg3){
        //    CODE here...
        console.log("3 args: "+arg1+", "+arg2+", "+arg3);
        return this;
    };

    console.log("multiFn is now initialized");

    //    redefine the function using the fnMap in the closure
    this.multiFn = function(){
        fnMap[arguments.length].apply(this, arguments);
        return this;
    };

    //    call the function since this code will only run once
    this.multiFn.apply(this, arguments);

    return this;    
};

اختبار.

TEST.multiFn("0")
    .multiFn()
    .multiFn("0","1","2");

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

    function optionsObjectTest(x, y, opts) {
        opts = opts || {}; // default to an empty options object

        var stringValue = opts.stringValue || "string default value";
        var boolValue = !!opts.boolValue; // coerces value to boolean with a double negation pattern
        var numericValue = opts.numericValue === undefined ? 123 : opts.numericValue;

        return "{x:" + x + ", y:" + y + ", stringValue:'" + stringValue + "', boolValue:" + boolValue + ", numericValue:" + numericValue + "}";

}

هنا مثال على كيفية استخدام خيارات كائن

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

function multiTypeFunc(param)
{
    if(typeof param == 'string') {
        alert("I got a string type parameter!!");
     }else if(typeof param == 'number') {
        alert("I got a number type parameter!!");
     }else if(typeof param == 'boolean') {
        alert("I got a boolean type parameter!!");
     }else if(typeof param == 'object') {
        alert("I got a object type parameter!!");
     }else{
        alert("error : the parameter is undefined or null!!");
     }
}

حظا سعيدا!

مقدمة

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

Function overloading Definition, Function Length property, Function argument property

Function overloading في أبسط أشكالها يعني أن وظيفة تؤدي مهام مختلفة على أساس عدد من الحجج التي يتم تمريرها إليه.ولا سيما TASK1, TASK2 و TASK3 أدناه ويجري تنفيذها على أساس عدد من arguments يتم تمريرها إلى نفس الوظيفة fooYo.

// if we have a function defined below
function fooYo(){
     // do something here
}
// on invoking fooYo with different number of arguments it should be capable to do different things

fooYo();  // does TASK1
fooYo('sagar'); // does TASK2
fooYo('sagar','munjal'); // does TAKS3

ملاحظة - JS لا توفر يحمل في ثناياه عوامل قدرة وظيفة الحمولة الزائدة.

البديل

جون ه Resig (الخالق JS) قد أشار إلى البديل الذي يستخدم أعلاه المتطلبات الأساسية لتحقيق القدرة على تنفيذ وظيفة الحمولة الزائدة.

رمز أدناه يستخدم واضحة ولكن من السذاجة النهج باستخدام if-else أو switch البيان.

  • يقيم argument-length مكان الإقامة.
  • قيم مختلفة نتيجة في الاحتجاج من وظائف مختلفة.

var ninja = {
  whatever: function() {
       switch (arguments.length) {
         case 0:
           /* do something */
           break;
         case 1:
           /* do something else */
           break;
         case 2:
           /* do yet something else */
           break;
       //and so on ...
    } 
  }
}

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

  • نحدد وظيفة addMethod والذي يستخدم لإضافة وظائف مختلفة إلى كائن مع نفس الاسم ولكن وظائف مختلفة.

  • تحت addMethod وظيفة يقبل ثلاثة params اسم الكائن object, اسم الدالة name و الدالة التي نريد أن يكون الاحتجاج fn.

  • داخل addMethod تعريف var old متجر المرجع السابق function يتم تخزينها من قبل مساعدة من الإغلاق واقية فقاعة.

function addMethod(object, name, fn) {
  var old = object[name];
  object[name] = function(){
    if (fn.length == arguments.length)
      return fn.apply(this, arguments)
    else if (typeof old == 'function')
      return old.apply(this, arguments);
  };
};

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

var ninja = {};
debugger;


addMethod(ninja,'whatever',function(){ console.log("I am the one with ZERO arguments supplied") });
addMethod(ninja,'whatever',function(a){ console.log("I am the one with ONE arguments supplied") });
addMethod(ninja,'whatever',function(a,b){ console.log("I am the one with TWO arguments supplied") });


ninja.whatever();
ninja.whatever(1,2);
ninja.whatever(3);

طريقة أخرى لمعالجة هذه هي باستخدام الخاصة متغير: الحجج, هذا هو تنفيذ:

function sum() {
    var x = 0;
    for (var i = 0; i < arguments.length; ++i) {
        x += arguments[i];
    }
    return x;
}

لذلك يمكنك تعديل هذه التعليمة البرمجية:

function sum(){
    var s = 0;
    if (typeof arguments[0] !== "undefined") s += arguments[0];
.
.
.
    return s;
}

التحقق من ذلك.هذا هو بارد جدا.http://ejohn.org/blog/javascript-method-overloading/ خدعة جافا سكريبت يسمح لك أن تفعل المكالمات مثل هذا:

var users = new Users();
users.find(); // Finds all
users.find("John"); // Finds users by name
users.find("John", "Resig"); // Finds users by first and last name

كما أن هذا المنصب بالفعل يحتوي على الكثير من الحلول المختلفة فكرت في بعد آخر.

function onlyUnique(value, index, self) {
    return self.indexOf(value) === index;
}

function overload() {
   var functions = arguments;
   var nroffunctionsarguments = [arguments.length];
    for (var i = 0; i < arguments.length; i++) {
        nroffunctionsarguments[i] = arguments[i].length;
    }
    var unique = nroffunctionsarguments.filter(onlyUnique);
    if (unique.length === arguments.length) {
        return function () {
            var indexoffunction = nroffunctionsarguments.indexOf(arguments.length);
            return functions[indexoffunction].apply(this, arguments);
        }
    }
    else throw new TypeError("There are multiple functions with the same number of parameters");

}

وهذا يمكن أن تستخدم كما هو مبين أدناه:

var createVector = overload(
        function (length) {
            return { x: length / 1.414, y: length / 1.414 };
        },
        function (a, b) {
            return { x: a, y: b };
        },
        function (a, b,c) {
            return { x: a, y: b, z:c};
        }
    );
console.log(createVector(3, 4));
console.log(createVector(3, 4,5));
console.log(createVector(7.07));

هذا الحل ليس مثاليا ولكن أريد فقط أن تثبت كيف يمكن القيام به.

يمكنك المستخدم 'addMethod من John Resig.مع هذا الأسلوب يمكنك "الزائد" أساليب بناء على الحجج العد.

// addMethod - By John Resig (MIT Licensed)
function addMethod(object, name, fn){
    var old = object[ name ];
    object[ name ] = function(){
        if ( fn.length == arguments.length )
            return fn.apply( this, arguments );
        else if ( typeof old == 'function' )
            return old.apply( this, arguments );
    };
}

أنا خلقت أيضا بديل هذا الأسلوب الذي يستخدم التخزين المؤقت إلى عقد الاختلافات الدالة. ديفيرينسيس الموضحة هنا

// addMethod - By Stavros Ioannidis
function addMethod(obj, name, fn) {
  obj[name] = obj[name] || function() {
    // get the cached method with arguments.length arguments
    var method = obj[name].cache[arguments.length];

    // if method exists call it 
    if ( !! method)
      return method.apply(this, arguments);
    else throw new Error("Wrong number of arguments");
  };

  // initialize obj[name].cache
  obj[name].cache = obj[name].cache || {};

  // Check if a method with the same number of arguments exists  
  if ( !! obj[name].cache[fn.length])
    throw new Error("Cannot define multiple '" + name +
      "' methods with the same number of arguments!");

  // cache the method with fn.length arguments
  obj[name].cache[fn.length] = function() {
    return fn.apply(this, arguments);
  };
}

توجيه نمط => أفضل الممارسات على شبيبة الحمولة الزائدة

إلى الأمام إلى وظيفة أخرى وهو اسم مبني من 3 & 4 نقاط :

  1. باستخدام عدد من الحجج
  2. التحقق من أنواع الحجج
window['foo_'+arguments.length+'_'+Array.from(arguments).map((arg)=>typeof arg).join('_')](...arguments)

تطبيق على الحالة :

 function foo(){
          return window['foo_'+arguments.length+Array.from(arguments).map((arg)=>typeof arg).join('_')](...arguments);

  }
   //------Assuming that `x` , `y` and `z` are String when calling `foo` . 

  /**-- for :  foo(x)*/
  function foo_1_string(){
  }
  /**-- for : foo(x,y,z) ---*/
  function foo_3_string_string_string(){

  }

المعقدة الأخرى العينة :

      function foo(){
          return window['foo_'+arguments.length+Array.from(arguments).map((arg)=>typeof arg).join('_')](...arguments);
       }

        /** one argument & this argument is string */
      function foo_1_string(){

      }
       //------------
       /** one argument & this argument is object */
      function foo_1_object(){

      }
      //----------
      /** two arguments & those arguments are both string */
      function foo_2_string_string(){

      }
       //--------
      /** Three arguments & those arguments are : id(number),name(string), callback(function) */
      function foo_3_number_string_function(){
                let args=arguments;
                  new Person(args[0],args[1]).onReady(args[3]);
      }

       //--- And so on ....   

وظيفة الحمولة الزائدة عبر ديناميكية تعدد الأشكال في 100 خطوط JS

هذا من الجسم أكبر من التعليمات البرمجية التي تشمل isFn, isArr, ، وما إلى ذلك.نوع التحقق من وظائف.على VanillaJS النسخة أدناه وقد تم إعادة صياغة لإزالة كافة التبعيات الخارجية ، ومع ذلك عليك أن تحدد أنت بنفسك نوع فحص وظائف للاستخدام في .add() المكالمات.

ملاحظة: هذا هو وظيفة ذاتية التنفيذ (لذلك نحن يمكن أن يكون الإغلاق/مغلقة نطاق) ، ومن ثم الإحالة إلى window.overload بدلا من function overload() {...}.

window.overload = function () {
    "use strict"

    var a_fnOverloads = [],
        _Object_prototype_toString = Object.prototype.toString
    ;

    function isFn(f) {
        return (_Object_prototype_toString.call(f) === '[object Function]');
    } //# isFn

    function isObj(o) {
        return !!(o && o === Object(o));
    } //# isObj

    function isArr(a) {
        return (_Object_prototype_toString.call(a) === '[object Array]');
    } //# isArr

    function mkArr(a) {
        return Array.prototype.slice.call(a);
    } //# mkArr

    function fnCall(fn, vContext, vArguments) {
        //# <ES5 Support for array-like objects
        //#     See: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/apply#Browser_compatibility
        vArguments = (isArr(vArguments) ? vArguments : mkArr(vArguments));

        if (isFn(fn)) {
            return fn.apply(vContext || this, vArguments);
        }
    } //# fnCall

    //# 
    function registerAlias(fnOverload, fn, sAlias) {
        //# 
        if (sAlias && !fnOverload[sAlias]) {
            fnOverload[sAlias] = fn;
        }
    } //# registerAlias

    //# 
    function overload(vOptions) {
        var oData = (isFn(vOptions) ?
                { default: vOptions } :
                (isObj(vOptions) ?
                    vOptions :
                    {
                        default: function (/*arguments*/) {
                            throw "Overload not found for arguments: [" + mkArr(arguments) + "]";
                        }
                    }
                )
            ),
            fnOverload = function (/*arguments*/) {
                var oEntry, i, j,
                    a = arguments,
                    oArgumentTests = oData[a.length] || []
                ;

                //# Traverse the oArgumentTests for the number of passed a(rguments), defaulting the oEntry at the beginning of each loop
                for (i = 0; i < oArgumentTests.length; i++) {
                    oEntry = oArgumentTests[i];

                    //# Traverse the passed a(rguments), if a .test for the current oArgumentTests fails, reset oEntry and fall from the a(rgument)s loop
                    for (j = 0; j < a.length; j++) {
                        if (!oArgumentTests[i].tests[j](a[j])) {
                            oEntry = undefined;
                            break;
                        }
                    }

                    //# If all of the a(rgument)s passed the .tests we found our oEntry, so break from the oArgumentTests loop
                    if (oEntry) {
                        break;
                    }
                }

                //# If we found our oEntry above, .fn.call its .fn
                if (oEntry) {
                    oEntry.calls++;
                    return fnCall(oEntry.fn, this, a);
                }
                //# Else we were unable to find a matching oArgumentTests oEntry, so .fn.call our .default
                else {
                    return fnCall(oData.default, this, a);
                }
            } //# fnOverload
        ;

        //# 
        fnOverload.add = function (fn, a_vArgumentTests, sAlias) {
            var i,
                bValid = isFn(fn),
                iLen = (isArr(a_vArgumentTests) ? a_vArgumentTests.length : 0)
            ;

            //# 
            if (bValid) {
                //# Traverse the a_vArgumentTests, processinge each to ensure they are functions (or references to )
                for (i = 0; i < iLen; i++) {
                    if (!isFn(a_vArgumentTests[i])) {
                        bValid = _false;
                    }
                }
            }

            //# If the a_vArgumentTests are bValid, set the info into oData under the a_vArgumentTests's iLen
            if (bValid) {
                oData[iLen] = oData[iLen] || [];
                oData[iLen].push({
                    fn: fn,
                    tests: a_vArgumentTests,
                    calls: 0
                });

                //# 
                registerAlias(fnOverload, fn, sAlias);

                return fnOverload;
            }
            //# Else one of the passed arguments was not bValid, so throw the error
            else {
                throw "poly.overload: All tests must be functions or strings referencing `is.*`.";
            }
        }; //# overload*.add

        //# 
        fnOverload.list = function (iArgumentCount) {
            return (arguments.length > 0 ? oData[iArgumentCount] || [] : oData);
        }; //# overload*.list

        //# 
        a_fnOverloads.push(fnOverload);
        registerAlias(fnOverload, oData.default, "default");

        return fnOverload;
    } //# overload

    //# 
    overload.is = function (fnTarget) {
        return (a_fnOverloads.indexOf(fnTarget) > -1);
    } //# overload.is

    return overload;
}();

الاستخدام:

المتصل وتعرف طاقتها وظائف عن طريق تعيين متغير عودة overload().بفضل تسلسل الإضافية الزائدة يمكن أن تكون محددة في سلسلة:

var myOverloadedFn = overload(function(){ console.log("default", arguments) })
    .add(function(){ console.log("noArgs", arguments) }, [], "noArgs")
    .add(function(){ console.log("str", arguments) }, [function(s){ return typeof s === 'string' }], "str")
;

واحد اختياري حجة overload() ويعرف "الافتراضي" وظيفة الاتصال إذا كان التوقيع لا يمكن تحديدها.الحجج .add() هي:

  1. fn: function تحديد التحميل الزائد ؛
  2. a_vArgumentTests: Array من functions تحديد اختبارات لتشغيل على arguments.كل function تقبل حجة واحدة و يعود trueخاصتك على أساس إذا كانت الحجة غير صحيحة ؛
  3. sAlias (اختياري): string تحديد الاسم المستعار الوصول مباشرة إلى الزائد وظيفة (fn) مثلا myOverloadedFn.noArgs() سيتم استدعاء هذه الدالة مباشرة ، وتجنب ديناميكية تعدد الاختبارات من الحجج.

هذا التطبيق يسمح في الواقع أكثر من مجرد التقليدية وظيفة الزائدة الثاني a_vArgumentTests حجة .add() في الممارسة يعرف أنواع مخصصة.لذلك يمكنك أن البوابة الحجج ليس فقط على أساس النوع ، ولكن على نطاقات أو قيم أو مجموعات من القيم!

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

الآن, هناك بعض المحاذير...كما جافا سكريبت كتبته فضفاضة, عليك أن تكون حذرا مع vArgumentTests كما integer يمكن التحقق من صحتها كما float, ، وما إلى ذلك.

JSCompress.com إصدار (1114 بايت ، 744 بايت g-مضغوط):

window.overload=function(){'use strict';function b(n){return'[object Function]'===m.call(n)}function c(n){return!!(n&&n===Object(n))}function d(n){return'[object Array]'===m.call(n)}function e(n){return Array.prototype.slice.call(n)}function g(n,p,q){if(q=d(q)?q:e(q),b(n))return n.apply(p||this,q)}function h(n,p,q){q&&!n[q]&&(n[q]=p)}function k(n){var p=b(n)?{default:n}:c(n)?n:{default:function(){throw'Overload not found for arguments: ['+e(arguments)+']'}},q=function(){var r,s,t,u=arguments,v=p[u.length]||[];for(s=0;s<v.length;s++){for(r=v[s],t=0;t<u.length;t++)if(!v[s].tests[t](u[t])){r=void 0;break}if(r)break}return r?(r.calls++,g(r.fn,this,u)):g(p.default,this,u)};return q.add=function(r,s,t){var u,v=b(r),w=d(s)?s.length:0;if(v)for(u=0;u<w;u++)b(s[u])||(v=_false);if(v)return p[w]=p[w]||[],p[w].push({fn:r,tests:s,calls:0}),h(q,r,t),q;throw'poly.overload: All tests must be functions or strings referencing `is.*`.'},q.list=function(r){return 0<arguments.length?p[r]||[]:p},l.push(q),h(q,p.default,'default'),q}var l=[],m=Object.prototype.toString;return k.is=function(n){return-1<l.indexOf(n)},k}();

يمكنك الآن لا وظيفة الحمولة الزائدة في ECMAScript 2018 دون polyfills ، والتحقق من فار طول/نوع ، وما إلى ذلك ، مجرد استخدام انتشار الجملة.

function foo(var1, var2, opts){
  // set default values for parameters
  const defaultOpts = {
    a: [1,2,3],
    b: true,
    c: 0.3289,
    d: "str",
  }
  // merge default and passed-in parameters
  // defaultOpts must go first!
  const mergedOpts = {...defaultOpts, ...opts};

  // you can now refer to parameters like b as mergedOpts.b,
  // or just assign mergedOpts.b to b
  console.log(mergedOpts.a);
  console.log(mergedOpts.b);
  console.log(mergedOpts.c);  
  console.log(mergedOpts.d);
}
// the parameters you passed in override the default ones
// all JS types are supported: primitives, objects, arrays, functions, etc.
let var1, var2="random var";
foo(var1, var2, {a: [1,2], d: "differentString"});

// parameter values inside foo:
//a: [1,2]
//b: true
//c: 0.3289
//d: "differentString"

ما نشر جملة?

البقية/انتشار خصائص ECMAScript اقتراح (المرحلة 4) يضيف انتشار خصائص الكائن حرفية.نسخ الخاصة enumerable خصائص من المقدمة كائن على كائن جديد. أكثر على mdn

ملاحظة:انتشار الجملة في حرفية كائن لا يعمل في حافة أي هو ميزة تجريبية. انظر التوافق المتصفح

الخيار الأول حقا تستحق الاهتمام لأنها الشيء جئت في معقدة جدا رمز الإعداد.لذا جوابي هو

  1. باستخدام أسماء مختلفة في المقام الأول

مع القليل ولكن من الضروري التلميح ، أسماء يجب أن تبدو مختلفة على جهاز الكمبيوتر ، ولكن ليس بالنسبة لك.اسم طاقتها وظائف مثل:func, func1, func2.

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

var foo;

// original 'foo' definition
foo = function(a) {
  console.log("a: " + a);
}

// define 'foo' to accept two arguments
foo = (function() {
  // store a reference to the previous definition of 'foo'
  var old = foo;

  // use inline function so that you can refer to it internally
  return function newFoo(a,b) {

    // check that the arguments.length == the number of arguments 
    // defined for 'newFoo'
    if (arguments.length == newFoo.length) {
      console.log("a: " + a);
      console.log("b: " + b);

    // else if 'old' is a function, apply it to the arguments
    } else if (({}).toString.call(old) === '[object Function]') {
      old.apply(null, arguments);
    }
  }
})();

foo(1);
> a: 1
foo(1,2);
> a: 1
> b: 2
foo(1,2,3)
> a: 1

وباختصار ، فإن استخدام الحياه يخلق النطاق المحلي ، مما يسمح لنا لتحديد خاصة متغير old لتخزين إشارة إلى التعريف الأولي وظيفة foo.هذه الدالة ثم يعود مضمنة وظيفة newFoo أن سجلات محتويات كل اثنين من الحجج إذا كان يتم تمرير بالضبط حجتين a و b أو يدعو old وظيفة إذا arguments.length !== 2.هذا النمط يمكن أن يتكرر أي عدد من المرات إلى تزويد متغير واحد مع عدة وظيفية مختلفة defitions.

جافا سكريبت هو مصنف اللغة ، أنا فقط أعتقد أنه من المنطقي أن الزائد طريقة/عمل فيما يتعلق عدد من params.ومن ثم أود أن أوصي التحقق إذا كانت المعلمة تم تعريف:

myFunction = function(a, b, c) {
     if (b === undefined && c === undefined ){
          // do x...
     }
     else {
          // do y...
     }
};

اعتبارا من تموز / يوليه 2017 التالية كانت تقنية شائعة.ملاحظة أننا يمكن أيضا إجراء نوع التحقق من خلال وظيفة.

function f(...rest){   // rest is an array
   console.log(rest.length);
   for (v of rest) if (typeof(v)=="number")console.log(v);
}
f(1,2,3);  // 3 1 2 3

للاستخدام الخاص بك ، كيف سيكون التعامل مع ES6 (لأنه بالفعل نهاية عام 2017):

const foo = (x, y, z) => {
  if (y && z) {
    // Do your foo(x, y, z); functionality
    return output;
  }
  // Do your foo(x); functionality
  return output;
}

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

شيئا مثل هذا يمكن القيام به على وظيفة الحمولة الزائدة.

function addCSS(el, prop, val) {
  return {
    2: function() {
      // when two arguments are set
      // now prop is an oject
      for (var i in prop) {
          el.style[i] = prop[i];
      }
    },
    3: function() {
      // when three arguments are set
      el.style[prop] = val;
    }
    }[arguments.length]();
}
// usage
var el = document.getElementById("demo");
addCSS(el, "color", "blue");
addCSS(el, {
    "backgroundColor": "black",
  "padding": "10px"
});

المصدر

قدمنا over.js لحل هذه المشكلة هو وسيلة أنيقة جدا.يمكنك القيام به:

var obj = {

  /**
   * Says something in the console.
   *
   * say(msg) - Says something once.
   * say(msg, times) - Says something many times.
   */
  say: Over(
    function(msg$string){
      console.info(msg$string);
    },
    function(msg$string, times$number){
      for (var i = 0; i < times$number; i++) this.say(msg$string);
    }
  )

};

لذلك أنا حقا أحب هذه الطريقة في فعل الأشياء التي وجدت في أسرار جافا سكريبت النينجا

function addMethod(object,name,fn){
  var old = object[name];
  object[name] = function(){
    if (fn.length == arguments.length){
      return fn.apply(this,arguments);
    } else if(typeof old == 'function'){
        return old.apply(this,arguments);
    }
  }
}

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

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

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

حيث من سلبيات اعتقد الكود في البداية غامضة قليلا...ولكن لست متأكدا من الآخرين ؟

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

function Clear(control)
{
  var o = typeof control !== "undefined" ? control : document.body;
  var children = o.childNodes;
  while (o.childNodes.length > 0)
    o.removeChild(o.firstChild);
}

الاستخدام:واضح () ؛ // مسح جميع الوثيقة

واضح(myDiv);// مسح لوحة المشار إليه من قبل myDiv

أود @AntouanK هذا النهج.غالبا ما أجد نفسي توفر وظيفة مع أرقام مختلفة o المعلمات و أنواع مختلفة.في بعض الأحيان أنها لا تتبع النظام.يمكنني استخدام الخريطة تبحث أنواع المعلمات:

findUDPServers: function(socketProperties, success, error) {
    var fqnMap = [];

    fqnMap['undefined'] = fqnMap['function'] = function(success, error) {
        var socketProperties = {name:'HELLO_SERVER'};

        this.searchServers(socketProperties, success, error);
    };

    fqnMap['object'] = function(socketProperties, success, error) {
        var _socketProperties = _.merge({name:'HELLO_SERVER'}, socketProperties || {});

        this.searchServers(_socketProperties, success, error);
    };

    fqnMap[typeof arguments[0]].apply(this, arguments);
}
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top