ฟังก์ชั่นโอเวอร์โหลดใน Javascript - แนวทางปฏิบัติที่ดีที่สุด


783

วิธีที่ดีที่สุดในการปลอมฟังก์ชั่นการโอเวอร์โหลดใน Javascript คืออะไร?

ฉันรู้ว่ามันเป็นไปไม่ได้ที่จะโอเวอร์โหลดฟังก์ชั่นใน Javascript เหมือนกับภาษาอื่น ๆ หากฉันต้องการฟังก์ชั่นที่มีการใช้สองครั้งfoo(x)และfoo(x,y,z)เป็นวิธีที่ดีที่สุด / ที่ต้องการ:

  1. ใช้ชื่ออื่นในตอนแรก
  2. ใช้อาร์กิวเมนต์ตัวเลือกเช่น y = y || 'default'
  3. ใช้จำนวนอาร์กิวเมนต์
  4. การตรวจสอบประเภทของข้อโต้แย้ง
  5. หรืออย่างไร

14
บางทีมันอาจจะมีประโยชน์ที่จะถามว่าทำไมคุณคิดว่าคุณต้องใช้ฟังก์ชันมากไป ฉันคิดว่ามันจะทำให้เราใกล้ชิดกับทางออกที่แท้จริง
เบรอตง

1
สิ่งนี้ถูกปิด แต่ฉันทำสิ่งต่อไปนี้: this.selectBy = {อินสแตนซ์: selectByInstance, // ข้อความของฟังก์ชัน: selectByText, // ค่าของฟังก์ชัน: selectByValue // Function};
ศูนย์นักโทษ

คำตอบของฉันแสดงให้เห็นถึงวิธีการทำฟังก์ชั่นเวลาทำงานมากเกินไปมันมีโทษความเร็วและฉันจะไม่แนะนำให้ทำตามข้อกำหนดของ Javascript การโอเวอร์โหลดฟังก์ชั่นเป็นงานที่รวบรวมเวลาจริงๆฉันเพียง แต่ให้คำตอบเพื่อวัตถุประสงค์ทางการศึกษาเท่านั้น
Keldon Alleyne

2
ในกรณีที่มีประโยชน์ฉันได้สร้างเฟรมเวิร์ก js น้ำหนักเบาซึ่งอนุญาตให้ใช้วิธีการพิมพ์มากเกินไป เห็นได้ชัดว่าข้อแม้เดียวกันนี้ใช้กับการทำงาน แต่มันทำงานได้ดีสำหรับความต้องการของฉันจนถึงตอนนี้และยังมีพื้นที่สำหรับการปรับปรุงค่อนข้างมาก: blog.pebbl.co.uk/2013/01/describejs.html#methodoverloading
Pebbl

คำตอบ:


602

วิธีที่ดีที่สุดในการทำฟังก์ชั่นการโหลดมากเกินไปด้วยพารามิเตอร์ไม่ได้ตรวจสอบความยาวของอาร์กิวเมนต์หรือชนิด การตรวจสอบประเภทจะทำให้โค้ดของคุณช้าลงและคุณจะได้สนุกกับอาร์เรย์อาร์เรย์โมฆะวัตถุ ฯลฯ

สิ่งที่นักพัฒนาส่วนใหญ่ทำคือการยึดติดกับวัตถุเป็นอาร์กิวเมนต์สุดท้ายของวิธีการของพวกเขา วัตถุนี้สามารถเก็บอะไรก็ได้

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"});

จากนั้นคุณสามารถจัดการได้อย่างไรก็ตามคุณต้องการวิธีการของคุณ [สลับถ้าอื่น - อื่น ๆ ]


43
คุณสามารถให้ตัวอย่างการใช้งาน foo () ที่แสดงวิธีการใช้ / อ้างอิงพารามิเตอร์ "opts" เหล่านี้ได้อย่างไร
Moe Howard

24
Moe // มันอาจจะเป็นแบบนี้ก็ได้ if(opts['test']) //if test param exists, do something.. if(opts['bar']) //if bar param exists, do something
Deckard

80
ฟังก์ชั่นนี้ไม่ทำงานมากไป การโอเวอร์โหลดฟังก์ชั่นมีสองฟังก์ชั่นแยกกันโดยใช้ชื่อเดียวกัน แต่มีพารามิเตอร์ต่างกัน สิ่งที่คุณกำลังอธิบายเป็นเพียงฟังก์ชั่นเดียวที่มีอาร์กิวเมนต์วัตถุในตอนท้าย
d512

66
@ user1334007 เป็นไปไม่ได้ที่จะมีฟังก์ชั่นโอเวอร์โหลดเหมือนที่คุณทำใน Java / .NET ใช่นี่ไม่ใช่การบรรทุกเกินพิกัดที่แน่นอน แต่มันทำงาน
epascarello

18
ฉันประหลาดใจที่ไม่มีใครถามสิ่งนี้อยู่แล้ว: ทำไมการตรวจสอบarguments.lengthไม่แนะนำ นอกจากนี้ฉันเคยมาที่นี่มาก่อนและอ่านสิ่งที่นักพัฒนาส่วนใหญ่ทำคือ ...แต่ฉันแน่ใจว่านี่เป็นที่เดียวที่ฉันเคยเห็น วิธีการดังกล่าวยังทำลายความหวานของวากยสัมพันธ์ของการมี 'เกิน'!
c24w

169

ฉันมักจะทำสิ่งนี้:

ค#:

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

JavaScript ที่เทียบเท่ากัน:

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' ใน javascript ซึ่งประเมินว่าเป็นเท็จในคำสั่ง if อย่างไรก็ตามนิยามฟังก์ชันไม่ได้ถ่ายทอดข้อมูลที่ p2 และ p3 เป็นทางเลือก หากคุณต้องการโหลดมากเกินไป jQuery ได้ตัดสินใจที่จะใช้วัตถุเป็นพารามิเตอร์ตัวอย่างเช่น jQuery.ajax (ตัวเลือก) ฉันเห็นด้วยกับพวกเขาว่านี่เป็นวิธีที่มีประสิทธิภาพและชัดเจนที่สุดในการโหลดเกินพิกัด แต่ฉันไม่ค่อยต้องการพารามิเตอร์ทางเลือกด่วนมากกว่าหนึ่งหรือสองตัว

แก้ไข: เปลี่ยนถ้าทดสอบตามข้อเสนอแนะของเอียน


16
พารามิเตอร์ที่ไม่ได้ระบุไว้undefinedใน JS nullไม่ ในฐานะที่เป็นวิธีที่ดีที่สุดที่คุณไม่ควรตั้งค่าอะไรที่จะดังนั้นจึงไม่ควรเป็นปัญหาตราบเท่าที่คุณเปลี่ยนทดสอบของคุณundefined p2 === undefined
Tamzin Blake

3
หากคุณผ่านfalseเป็นอาร์กิวเมนต์สุดท้ายแล้วมันจะไม่เชื่อมต่อกัน"false"จนจบเพราะif(p3)จะไม่สาขา
dreamlax

5
เพียงแค่บันทึกย่อของคุณtypeof p2 === "undefined"อาจเป็นสิ่งที่ตรงกันข้ามกับสิ่งที่คุณคาดหวังในตัวอย่างของคุณฉันคิดว่าtypeof p2 !== "undefined"เป็นสิ่งที่คุณตั้งใจ นอกจากนี้ฉันขอแนะนำให้มันควรจะเชื่อมโยงสตริงจำนวนและบูลีนที่คุณทำจริง ๆp2 === "number"; p3 === "boolean"
WillFM

8
ฉันชอบทำสิ่งนี้: p3 = p3 || 'ค่าเริ่มต้น';
Dorian

3
ความหมายของคืออะไร===และ!==? ทำไมไม่ใช้==และเพียง!=?
Ricardo Cruz

76

ไม่มีฟังก์ชั่นการทำงานหนักเกินจริงใน JavaScript เนื่องจากอนุญาตให้ส่งผ่านพารามิเตอร์จำนวนเท่าใดก็ได้ คุณต้องตรวจสอบภายในฟังก์ชั่นว่ามีการส่งผ่านอาร์กิวเมนต์จำนวนเท่าใดและเป็นประเภทใด


1
John Resig (จาก jQuery) เคยลองสิ่งนี้แล้ว แต่ความพยายามนั้นเป็นเรื่องทางวิชาการอย่างแท้จริงและไม่ได้ให้ประโยชน์ใด ๆ เลย
scunliffe

14
ฟังก์ชันของ John Resig โอเวอร์โหลดที่นี่ejohn.org/blog/javascript-method-overloading
Terrance

@Terrance: ฉันชอบวิธีของ Resig ด้วย มันทำงานเหมือนจับใจ ฉันแค่ต้องหาวิธีในการสร้างการทดสอบเพื่อตรวจสอบกรณีการใช้งาน
chrisvillanueva

"ฟังก์ชั่นนี้จะไม่เปลี่ยนแปลงโลก แต่มันสั้นกระชับและใช้คุณสมบัติ JavaScript ที่คลุมเครือดังนั้นมันจึงชนะในหนังสือของฉัน" :-)
Frerich Raabe

67

คำตอบที่ถูกต้องคือไม่มีการโอเวอร์โหลดใน JAVASCRIPT

การตรวจสอบ / การสลับข้างในฟังก์ชั่นนั้นไม่ใช่การโอเวอร์โหลด

แนวคิดของการโอเวอร์โหลด: ในบางภาษาการเขียนโปรแกรมฟังก์ชั่นการโหลดมากเกินไปหรือการโอเวอร์โหลดวิธีการคือความสามารถในการสร้างหลายวิธีในชื่อเดียวกันกับการใช้งานที่แตกต่างกัน การเรียกใช้ฟังก์ชันที่โอเวอร์โหลดจะเรียกใช้การใช้งานเฉพาะของฟังก์ชันนั้นที่เหมาะสมกับบริบทของการโทรทำให้การเรียกใช้ฟังก์ชันหนึ่งสามารถทำงานที่แตกต่างกันขึ้นอยู่กับบริบท

ตัวอย่างเช่น doTask () และ doTask (object O) เป็นวิธีโอเวอร์โหลด ในการเรียกใช้หลังวัตถุต้องถูกส่งผ่านเป็นพารามิเตอร์ในขณะที่วัตถุเก่าไม่ต้องการพารามิเตอร์และถูกเรียกด้วยฟิลด์พารามิเตอร์ว่าง ข้อผิดพลาดทั่วไปคือการกำหนดค่าเริ่มต้นให้กับวัตถุในวิธีที่สองซึ่งจะส่งผลให้เกิดข้อผิดพลาดในการโทรที่ไม่ชัดเจนเนื่องจากคอมไพเลอร์ไม่ทราบว่าจะใช้วิธีใดในสองวิธีนี้

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

การใช้งานที่แนะนำทั้งหมดนั้นยอดเยี่ยม แต่จริง ๆ แล้วต้องบอกว่าไม่มีการใช้งานจริงสำหรับ JavaScript


4
ในที่สุดก็เป็นคำตอบปกติ! ไม่มีโอเวอร์โหลดใน JAVASCRIPT
Razvan Tudorica

4
OP ขอวิธีการโอเวอร์โหลดปลอม
Ateur Games

อย่างที่ฉันเคยพูดมาก่อนเราอยู่ที่นี่ให้การศึกษาแก่ผู้คนเราไม่เพียง แต่ให้คำตอบแก่พวกเขาโดยไม่ยืนยันว่าสิ่งที่พวกเขาถามนั้นถูกต้อง
Marco

27

มีสองวิธีที่คุณสามารถเข้าถึงวิธีนี้ได้ดีกว่า:

  1. ผ่านพจนานุกรม (อาเรย์แบบเชื่อมโยง) หากคุณต้องการความยืดหยุ่นอย่างมาก

  2. ใช้วัตถุเป็นอาร์กิวเมนต์และใช้การสืบทอดตามต้นแบบเพื่อเพิ่มความยืดหยุ่น


1
นี่เป็นความคิดเริ่มต้นของฉันอย่างไรก็ตามหากฟังก์ชั่นที่คุณกำลังสร้างจะถูกใช้ในห้องสมุดหรือโดยคนอื่น ๆ การแจกแจงค่าที่ชัดเจนสามารถเป็นประโยชน์ได้
roberthuttinger

19

นี่คือวิธีการที่ช่วยให้การโอเวอร์โหลดวิธีการจริงโดยใช้ประเภทพารามิเตอร์ดังแสดงด้านล่าง:

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

แก้ไข (2018) : ตั้งแต่นี้ถูกเขียนขึ้นในปี 2011 ความเร็วของการเรียกใช้เมธอดโดยตรงได้เพิ่มขึ้นอย่างมากในขณะที่ความเร็วของวิธีการโอเวอร์โหลดไม่ได้

ไม่ใช่วิธีที่ฉันจะแนะนำ แต่เป็นการฝึกคิดที่คุ้มค่าที่จะคิดว่าคุณจะแก้ปัญหาประเภทนี้ได้อย่างไร


นี่เป็นมาตรฐานของวิธีการที่แตกต่างกัน - https://jsperf.com/function-overloading มันแสดงให้เห็นว่าฟังก์ชั่นการบรรทุกเกินพิกัด (การประเภทเข้าบัญชี) สามารถจะประมาณ13 ครั้งช้าใน Google Chrome ของ V816.0 (เบต้า)

เช่นเดียวกับการส่งผ่านวัตถุ (เช่น{x: 0, y: 0}) เราสามารถใช้แนวทาง C เมื่อเหมาะสมโดยตั้งชื่อวิธีการตามนั้น ตัวอย่างเช่น Vector.AddVector (เวกเตอร์), Vector.AddIntegers (x, y, z, ... ) และ Vector.AddArray (integerArray) คุณสามารถดูไลบรารี C เช่น OpenGL สำหรับการตั้งชื่อแรงบันดาลใจ

แก้ไข : ฉันได้เพิ่มมาตรฐานสำหรับการส่งผ่านวัตถุและการทดสอบสำหรับวัตถุโดยใช้ทั้ง'param' in argและarg.hasOwnProperty('param')และฟังก์ชั่นโอเวอร์โหลดเร็วกว่าการส่งผ่านวัตถุและการตรวจสอบสำหรับคุณสมบัติ (ในมาตรฐานนี้อย่างน้อย)

จากมุมมองของการออกแบบฟังก์ชั่นการโอเวอร์โหลดนั้นจะถูกต้องหรือมีเหตุผลเท่านั้นหากพารามิเตอร์ที่โอเวอร์โหลดนั้นสอดคล้องกับการกระทำเดียวกัน ดังนั้นจึงเป็นเหตุผลว่าควรมีวิธีการพื้นฐานที่เกี่ยวข้องกับรายละเอียดเฉพาะเท่านั้นมิฉะนั้นอาจบ่งบอกถึงตัวเลือกการออกแบบที่ไม่เหมาะสม ดังนั้นหนึ่งสามารถแก้ไขการใช้ฟังก์ชั่นมากเกินไปโดยการแปลงข้อมูลเป็นวัตถุที่เกี่ยวข้อง แน่นอนว่าต้องพิจารณาขอบเขตของปัญหาเนื่องจากไม่จำเป็นต้องออกแบบอย่างประณีตหากคุณตั้งใจจะพิมพ์ชื่อ แต่สำหรับการออกแบบกรอบงานและห้องสมุดความคิดเช่นนั้นเป็นธรรม

ตัวอย่างของฉันมาจากการนำไปใช้งานแบบสี่เหลี่ยมผืนผ้า - ดังนั้นการกล่าวถึงมิติและจุด บางที Rectangle สามารถเพิ่ม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);

16

วิธีที่ดีที่สุดขึ้นอยู่กับฟังก์ชั่นและข้อโต้แย้ง ตัวเลือกแต่ละอย่างของคุณเป็นความคิดที่ดีในสถานการณ์ที่แตกต่างกัน ฉันมักจะลองตามลำดับต่อไปนี้จนกว่าจะมีหนึ่งในนั้นทำงาน:

  1. ใช้อาร์กิวเมนต์ที่เป็นตัวเลือกเช่น y = y || 'ค่าเริ่มต้น'. วิธีนี้จะสะดวกถ้าคุณทำได้ แต่อาจไม่ได้ผลจริงเช่นเมื่อ 0 / null / ไม่ได้กำหนดจะเป็นอาร์กิวเมนต์ที่ถูกต้อง

  2. ใช้จำนวนอาร์กิวเมนต์ คล้ายกับตัวเลือกสุดท้าย แต่อาจทำงานได้เมื่อ # 1 ไม่ทำงาน

  3. การตรวจสอบประเภทของข้อโต้แย้ง สิ่งนี้สามารถทำงานได้ในบางกรณีที่จำนวนข้อโต้แย้งเท่ากัน หากคุณไม่สามารถระบุประเภทที่เชื่อถือได้คุณอาจต้องใช้ชื่ออื่น

  4. ใช้ชื่ออื่นในตอนแรก คุณอาจต้องทำสิ่งนี้หากตัวเลือกอื่นใช้ไม่ได้ผลไม่ได้ผลหรือเพื่อความสอดคล้องกับฟังก์ชั่นอื่น ๆ ที่เกี่ยวข้อง


14

ถ้าฉันต้องการฟังก์ชั่นที่มีสองอันใช้ foo (x) และ foo (x, y, z) ซึ่งเป็นวิธีที่ดีที่สุด / เป็นที่ต้องการ?

ปัญหาคือ JavaScript ไม่สนับสนุนวิธีการโหลดมากเกินไป ดังนั้นหากมันเห็น / แยกวิเคราะห์สองฟังก์ชันขึ้นไปที่มีชื่อเหมือนกันมันจะพิจารณาฟังก์ชั่นที่กำหนดล่าสุดและเขียนทับฟังก์ชันก่อนหน้า

หนึ่งในวิธีที่ฉันคิดว่าเหมาะสำหรับกรณีส่วนใหญ่มีดังนี้ -

ให้บอกว่าคุณมีวิธี

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: ลิงค์ด้านบนไปที่บล็อกส่วนตัวของฉันที่มีรายละเอียดเพิ่มเติม


9

ฉันไม่แน่ใจเกี่ยวกับแนวปฏิบัติที่ดี แต่นี่คือวิธีที่ฉันทำ:

/*
 * 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"

2
@Luis: ฉันได้เพิ่มความคิดเห็นที่เป็นประโยชน์หวังว่าบางอย่าง
chessweb

6

ฉันแค่ลองสิ่งนี้บางทีมันอาจจะเหมาะกับความต้องการของคุณ ขึ้นอยู่กับจำนวนของข้อโต้แย้งที่คุณสามารถเข้าถึงฟังก์ชั่นที่แตกต่างกัน คุณเริ่มต้นมันในครั้งแรกที่คุณเรียกมัน และแผนที่ฟังก์ชั่นถูกซ่อนอยู่ในการปิด

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");

5

เนื่องจากจาวาสคริปต์ไม่มีฟังก์ชั่นโอเวอร์โหลดตัวเลือกวัตถุสามารถใช้แทน หากมีข้อโต้แย้งที่จำเป็นหนึ่งหรือสองข้อจะเป็นการดีกว่าที่จะแยกออกจากตัวเลือกวัตถุ นี่คือตัวอย่างเกี่ยวกับวิธีใช้อ็อพเจ็กอ็อพชั่นและค่าที่เติมเข้าไปในค่าปริยายในกรณีที่ค่าไม่ได้ผ่านในออปเจ็กต์อ๊อพชั่น

    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 + "}";

}

นี่คือตัวอย่างเกี่ยวกับวิธีใช้อ็อพเจ็กอ็อพชั่น


4

ไม่มีวิธีในการทำงานมากเกินไปในจาวาสคริปต์ ดังนั้นฉันขอแนะนำวิธีต่อไปนี้ตาม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!!");
     }
}

โชคดี!


24
เพื่อประโยชน์ของพระเจ้า! ใช้คำสั่งเปลี่ยน!
jedmao

8
นอกจากนี้หากคุณยืนยันว่าไม่ได้ใช้สวิตช์คุณควรโทรหา typeof หนึ่งครั้งเท่านั้น var type = typeof param; if (type === 'string') ...
วอลเตอร์ Stabosz

+1 เพื่อแสดงความคิดเห็นสำหรับ "===" ข้อได้เปรียบอื่น ๆ ของคำสั่งเปลี่ยนไปถ้า (... == ... ) มันเป็นประเภทที่ปลอดภัย
Nathan Cooper

4

บทนำ

จนถึงการอ่านคำตอบมากมายจะทำให้ทุกคนปวดหัว ทุกคนพยายามที่จะรู้ว่าแนวความคิดจะต้องรู้ว่าสิ่งที่จำเป็นต่อไปนี้ s

Function overloading Definition, Function Length property,Function argument property

Function overloadingในรูปแบบที่ง่ายที่สุดหมายความว่าฟังก์ชั่นดำเนินงานที่แตกต่างกันบนพื้นฐานของจำนวนข้อโต้แย้งที่ถูกส่งผ่านไปยังมัน สะดุดตา TASK1, TASK2 และ TASK3 เป็นไฮไลต์ด้านล่างและมีการดำเนินการบนพื้นฐานของจำนวนที่ถูกส่งผ่านไปยังฟังก์ชั่นเดียวกันargumentsfooYo

// 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

NOTE - JS ไม่ได้จัดเตรียมความสามารถของการโอเวอร์โหลดฟังก์ชันในตัว

ทางเลือก

John E 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ฟังก์ชั่นยอมรับสามชื่อวัตถุพารามิเตอร์ชื่อ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);


4

อีกวิธีหนึ่งในการเข้าถึงสิ่งนี้คือการใช้ตัวแปรพิเศษ: อาร์กิวเมนต์นี่คือการนำไปใช้:

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;
}

3

ลองดู. มันเจ๋งมาก http://ejohn.org/blog/javascript-method-overloading/ Trick Javascript เพื่อให้คุณโทรออกได้เช่นนี้:

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

สวัสดี Jaider ลองดูคำตอบของฉันมันมีรหัสสำหรับการใช้งานจาวาสคริปต์จริงมากเกินไป ฉันกำลังพูดFunc(new Point())และFunc(new Rectangle())จะใช้งานฟังก์ชั่นต่าง ๆ แต่ฉันต้องชี้ให้เห็นว่านี่เป็นแฮ็คที่สกปรกเนื่องจากวิธีการโอเวอร์โหลดนั้นเป็นงานที่รวบรวมเวลาไม่ใช่เวลาทำงาน
Keldon Alleyne

3

ฟังก์ชั่นโอเวอร์โหลดใน Javascript:

การโอเวอร์โหลดฟังก์ชั่นเป็นความสามารถของภาษาการเขียนโปรแกรมเพื่อสร้างฟังก์ชั่นหลายอย่างในชื่อเดียวกันกับการใช้งานที่แตกต่างกัน เมื่อมีการเรียกใช้ฟังก์ชันที่โอเวอร์โหลดมันจะเรียกใช้ฟังก์ชันการใช้งานเฉพาะของฟังก์ชันนั้นที่เหมาะสมกับบริบทของการโทร บริบทนี้มักจะได้รับจำนวนของข้อโต้แย้งและช่วยให้การเรียกใช้ฟังก์ชันหนึ่งทำงานแตกต่างกันไปขึ้นอยู่กับบริบท

Javascript ไม่มีฟังก์ชั่นการทำงานหนักเกินไป อย่างไรก็ตามพฤติกรรมนี้สามารถเลียนแบบได้หลายวิธี นี่คือหนึ่งง่ายสะดวก:

function sayHi(a, b) {
  console.log('hi there ' + a);
  if (b) { console.log('and ' + b) } // if the parameter is present, execute the block
}

sayHi('Frank', 'Willem');

ในสถานการณ์ที่คุณไม่ทราบว่าหลายข้อโต้แย้งคุณจะได้รับคุณสามารถใช้ประกอบการส่วนที่เหลือ...ซึ่งเป็นจุดสามจุด มันจะแปลงส่วนที่เหลือของข้อโต้แย้งเป็นอาร์เรย์ ระวังความเข้ากันได้ของเบราว์เซอร์ นี่คือตัวอย่าง:

function foo (a, ...b) {
  console.log(b);
}

foo(1,2,3,4);
foo(1,2);


2

เนื่องจากโพสต์นี้มีโซลูชันต่าง ๆ มากมายฉันคิดว่าฉันโพสต์อีก

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));

โซลูชันนี้ไม่สมบูรณ์ แต่ฉันต้องการเพียงแสดงให้เห็นว่าสามารถทำได้


2

คุณสามารถใช้ '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);
  };
}

2

รูปแบบการส่งต่อ => แนวปฏิบัติที่เหมาะสมที่สุดสำหรับการโอเวอร์โหลด JS

ส่งต่อไปยังฟังก์ชันอื่นซึ่งชื่อถูกสร้างขึ้นจากจุดที่ 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 ....   

2

ฟังก์ชั่นโอเวอร์โหลดผ่าน Dynamic Polymorphism ใน 100 บรรทัดของ JS

  • VanillaJS ไม่มีการพึ่งพาภายนอก
  • การสนับสนุนเบราว์เซอร์แบบเต็ม - Array.prototype.slice , Object.prototype.toString
  • 1114 ไบต์ uglify'd / 744 ไบต์ g-zipped

นี้เป็นจากร่างกายขนาดใหญ่ของรหัสซึ่งรวมถึงisFn, isArrฯลฯ ประเภทฟังก์ชั่นการตรวจสอบ รุ่น VanillaJS ด้านล่างนี้ได้รับการทำใหม่เพื่อลบการอ้างอิงภายนอกทั้งหมดอย่างไรก็ตามคุณจะต้องกำหนดว่าคุณเป็นเจ้าของฟังก์ชั่นตรวจสอบประเภทเพื่อใช้ในการ.add()โทร

หมายเหตุ:นี่คือฟังก์ชั่นในตัวเองการดำเนินการ (เพื่อให้เราสามารถมีขอบเขตการปิด / ปิด) จึงมอบหมายให้มากกว่าwindow.overloadfunction 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}();

2

ตอนนี้คุณสามารถทำฟังก์ชั่นการบรรทุกเกินพิกัดใน ECMAScript 2018 โดยไม่ต้อง polyfills ตรวจสอบความยาว var / ประเภทอื่น ๆเพียงแค่ใช้ไวยากรณ์การแพร่กระจาย

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) เพิ่มคุณสมบัติการแพร่กระจายไปยังตัวอักษรวัตถุ มันคัดลอกคุณสมบัติที่นับได้ของตัวเองจากวัตถุที่ให้ไปยังวัตถุใหม่ เพิ่มเติมเกี่ยวกับ mdn

หมายเหตุ: สเปรดไวยากรณ์ในวัตถุตัวอักษรไม่ได้ทำงานใน Edge และ IE และเป็นคุณสมบัติทดลอง ดูความเข้ากันได้เบราว์เซอร์


2

สิ่งนี้สามารถทำได้สำหรับการทำงานมากเกินไป

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"
});

แหล่ง


1

นี่เป็นคำถามเก่า แต่อย่างหนึ่งที่ฉันคิดว่าจำเป็นต้องมีรายการอื่น (แม้ว่าฉันจะสงสัยว่าใครจะอ่าน) การใช้ฟังก์ชั่นการเรียกใช้งานทันทีที่เรียกใช้ (IIFE) สามารถใช้ร่วมกับฟังก์ชั่นปิดและฟังก์ชั่นอินไลน์เพื่อให้ฟังก์ชั่นโอเวอร์โหลด ลองพิจารณาตัวอย่าง (contrived) ต่อไปนี้:

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

ในระยะสั้นการใช้ IIFE สร้างขอบเขตท้องถิ่นช่วยให้เราสามารถกำหนดตัวแปรส่วนตัวในการจัดเก็บการอ้างอิงถึงคำนิยามของการเริ่มต้นของการทำงานold fooฟังก์ชั่นนี้แล้วส่งกลับฟังก์ชั่นแบบอินไลน์newFooที่บันทึกเนื้อหาของทั้งสองมีปากเสียงถ้ามันจะถูกส่งตรงสองมีปากเสียงaและbหรือเรียกฟังก์ชั่นถ้าold arguments.length !== 2รูปแบบนี้สามารถทำซ้ำได้หลาย ๆ ครั้งเพื่อมอบหนึ่งตัวแปรที่มีฟังก์ชั่นการปกป้องที่หลากหลาย


1

ฉันต้องการแบ่งปันตัวอย่างที่เป็นประโยชน์ของวิธีการที่คล้ายกันมากเกินไป

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


1

JavaScript เป็นภาษาที่ไม่มีการพิมพ์และฉันคิดว่ามันเหมาะสมที่จะโอเวอร์โหลดเมธอด / ฟังก์ชั่นที่เกี่ยวกับจำนวนของพารามิเตอร์ ดังนั้นฉันขอแนะนำให้ตรวจสอบว่าพารามิเตอร์ได้รับการกำหนด:

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

1
เพียงแค่ต้องการทราบว่า untyped ไม่ได้หมายความว่า "ไม่มีประเภท"
hamdiakoguz

1

เมื่อวันที่กรกฎาคม 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

1

สำหรับกรณีการใช้งานของคุณนี่เป็นวิธีที่ฉันจะจัดการกับES6(ตั้งแต่ตอนปลายปี 2560):

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

เห็นได้ชัดว่าคุณสามารถปรับสิ่งนี้ให้ทำงานกับพารามิเตอร์จำนวนเท่าใดก็ได้และเพียงแค่เปลี่ยนคำแถลงตามเงื่อนไขของคุณ


1

ไม่มีการโหลดเกินจริงใน JS อย่างไรก็ตามเรายังสามารถจำลองวิธีการโอเวอร์โหลดได้หลายวิธี:

วิธีที่ # 1: ใช้วัตถุ

function test(x,options){
  if("a" in options)doSomething();
  else if("b" in options)doSomethingElse();
}
test("ok",{a:1});
test("ok",{b:"string"});

เมธอด # 2: ใช้พารามิเตอร์ rest (spread)

function test(x,...p){
 if(p[2])console.log("3 params passed"); //or if(typeof p[2]=="string")
else if (p[1])console.log("2 params passed");
else console.log("1 param passed");
}

วิธีที่ # 3: ใช้ไม่ได้กำหนด

function test(x, y, z){
 if(typeof(z)=="undefined")doSomething();
}

วิธีที่ # 4: การ ตรวจสอบประเภท

function test(x){
 if(typeof(x)=="string")console.log("a string passed")
 else ...
}

1

แม้ว่าพารามิเตอร์เริ่มต้นจะไม่ทำงานหนักเกินไป แต่อาจแก้ไขปัญหาที่นักพัฒนาเผชิญในพื้นที่นี้ การป้อนข้อมูลจะถูกตัดสินใจโดยคำสั่งอย่างเคร่งครัดคุณไม่สามารถสั่งซื้อซ้ำได้ตามที่คุณต้องการเช่นเดียวกับการโอเวอร์โหลดแบบคลาสสิก:

function transformer(
    firstNumber = 1,
    secondNumber = new Date().getFullYear(),
    transform = function multiply(firstNumber, secondNumber) {
        return firstNumber * secondNumber;
    }
) {
    return transform(firstNumber, secondNumber);
}

console.info(transformer());
console.info(transformer(8));
console.info(transformer(2, 6));
console.info(transformer(undefined, 65));

function add(firstNumber, secondNumber) {
    return firstNumber + secondNumber;
}
console.info(transformer(undefined, undefined, add));
console.info(transformer(3, undefined, add));

ผลลัพธ์ใน (สำหรับปี 2020):

2020
16160
12
65
2021
2023

ข้อมูลเพิ่มเติม: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Default_parameters


0

ตัวเลือกแรกสมควรได้รับความสนใจจริง ๆ เพราะมันเป็นสิ่งที่ฉันคิดขึ้นมาในการตั้งค่าโค้ดที่ค่อนข้างซับซ้อน ดังนั้นคำตอบของฉันคือ

  1. ใช้ชื่ออื่นในตอนแรก

ด้วยคำใบ้เล็กน้อย แต่จำเป็นชื่อควรดูต่างออกไปสำหรับคอมพิวเตอร์ แต่ไม่ใช่สำหรับคุณ ชื่อฟังก์ชั่นโอเวอร์โหลดเช่น: func, func1, func2


ฉันจะลองใช้งานมากเกินไป แต่ตัดสินใจใช้ชื่ออื่นเช่น
getDeviceInfoByID และ getDeviceInfoByType
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.