มีหลายแง่มุมในการโต้แย้งการโอเวอร์โหลดใน Javascript:
อาร์กิวเมนต์ตัวแปร - คุณสามารถส่งผ่านชุดของอาร์กิวเมนต์ที่แตกต่างกัน (ทั้งในประเภทและปริมาณ) และฟังก์ชันจะทำงานในลักษณะที่ตรงกับอาร์กิวเมนต์ที่ส่งผ่านไป
อาร์กิวเมนต์เริ่มต้น - คุณสามารถกำหนดค่าเริ่มต้นสำหรับอาร์กิวเมนต์ได้หากไม่มีการส่งผ่าน
อาร์กิวเมนต์ที่ตั้งชื่อ - ลำดับอาร์กิวเมนต์ไม่เกี่ยวข้องและคุณเพียงแค่ตั้งชื่ออาร์กิวเมนต์ที่คุณต้องการส่งผ่านไปยังฟังก์ชัน
ด้านล่างนี้เป็นหัวข้อเกี่ยวกับการจัดการอาร์กิวเมนต์แต่ละประเภทเหล่านี้
อาร์กิวเมนต์ตัวแปร
เนื่องจาก javascript ไม่มีการตรวจสอบประเภทของอาร์กิวเมนต์หรือจำนวนอาร์กิวเมนต์ที่ต้องการคุณสามารถมีการใช้งานเพียงครั้งเดียวmyFunc()ซึ่งสามารถปรับให้เข้ากับอาร์กิวเมนต์ที่ส่งผ่านไปได้โดยการตรวจสอบประเภทการมีอยู่หรือปริมาณของอาร์กิวเมนต์
jQuery ทำสิ่งนี้ตลอดเวลา คุณสามารถสร้างอาร์กิวเมนต์บางส่วนให้เป็นทางเลือกหรือคุณสามารถแตกแขนงในฟังก์ชันของคุณขึ้นอยู่กับว่าอาร์กิวเมนต์ใดถูกส่งไปยังอาร์กิวเมนต์นั้น
ในการใช้งานโอเวอร์โหลดประเภทนี้คุณมีเทคนิคต่างๆมากมายที่คุณสามารถใช้ได้:
- คุณสามารถตรวจสอบการมีอยู่ของอาร์กิวเมนต์ที่กำหนดโดยการตรวจสอบเพื่อดูว่าค่าชื่ออาร์กิวเมนต์ที่ประกาศคือ
undefinedหรือไม่
arguments.lengthคุณสามารถตรวจสอบปริมาณรวมหรือข้อโต้แย้งกับ
- คุณสามารถตรวจสอบประเภทของอาร์กิวเมนต์ที่กำหนด
- สำหรับตัวเลขตัวแปรของการขัดแย้ง, คุณสามารถใช้
argumentsหลอกอาร์เรย์ในการเข้าถึงการโต้แย้งใด ๆ arguments[i]ให้กับ
นี่คือตัวอย่างบางส่วน:
ลองดูobj.data()วิธีการของ jQuery รองรับการใช้งานสี่รูปแบบที่แตกต่างกัน:
obj.data("key");
obj.data("key", value);
obj.data();
obj.data(object);
แต่ละตัวก่อให้เกิดพฤติกรรมที่แตกต่างกันและหากไม่ใช้รูปแบบไดนามิกของการโอเวอร์โหลดนี้จะต้องใช้ฟังก์ชันแยกกันสี่ฟังก์ชัน
นี่คือวิธีที่เราสามารถแยกแยะระหว่างตัวเลือกเหล่านี้ทั้งหมดเป็นภาษาอังกฤษจากนั้นฉันจะรวมเข้าด้วยกันทั้งหมดในรหัส:
// get the data element associated with a particular key value
obj.data("key");
หากอาร์กิวเมนต์แรกที่ส่งไปยัง.data()เป็นสตริงและอาร์กิวเมนต์ที่สองคือundefinedผู้เรียกต้องใช้แบบฟอร์มนี้
// set the value associated with a particular key
obj.data("key", value);
หากไม่ได้กำหนดอาร์กิวเมนต์ที่สองให้ตั้งค่าของคีย์เฉพาะ
// get all keys/values
obj.data();
หากไม่มีการส่งผ่านอาร์กิวเมนต์ให้ส่งคืนคีย์ / ค่าทั้งหมดในอ็อบเจ็กต์ที่ส่งคืน
// set all keys/values from the passed in object
obj.data(object);
หากประเภทของอาร์กิวเมนต์แรกเป็นวัตถุธรรมดาให้ตั้งค่าคีย์ / ค่าทั้งหมดจากวัตถุนั้น
นี่คือวิธีที่คุณสามารถรวมสิ่งเหล่านี้ทั้งหมดไว้ในตรรกะ javascript ชุดเดียว:
// method declaration for .data()
data: function(key, value) {
if (arguments.length === 0) {
// .data()
// no args passed, return all keys/values in an object
} else if (typeof key === "string") {
// first arg is a string, look at type of second arg
if (typeof value !== "undefined") {
// .data("key", value)
// set the value for a particular key
} else {
// .data("key")
// retrieve a value for a key
}
} else if (typeof key === "object") {
// .data(object)
// set all key/value pairs from this object
} else {
// unsupported arguments passed
}
},
กุญแจสำคัญของเทคนิคนี้คือการตรวจสอบให้แน่ใจว่าข้อโต้แย้งทุกรูปแบบที่คุณต้องการยอมรับนั้นสามารถระบุตัวตนได้โดยไม่ซ้ำกันและไม่มีความสับสนว่าผู้โทรใช้รูปแบบใด โดยทั่วไปต้องเรียงลำดับอาร์กิวเมนต์อย่างเหมาะสมและตรวจสอบให้แน่ใจว่าประเภทและตำแหน่งของอาร์กิวเมนต์มีเอกลักษณ์เพียงพอที่คุณสามารถบอกได้ว่ากำลังใช้รูปแบบใด
ตัวอย่างเช่นหากคุณมีฟังก์ชันที่รับอาร์กิวเมนต์สตริงสามตัว:
obj.query("firstArg", "secondArg", "thirdArg");
คุณสามารถทำให้อาร์กิวเมนต์ที่สามเป็นทางเลือกได้อย่างง่ายดายและคุณสามารถตรวจพบเงื่อนไขนั้นได้อย่างง่ายดาย แต่คุณไม่สามารถทำให้อาร์กิวเมนต์ที่สองเป็นทางเลือกได้เท่านั้นเนื่องจากคุณไม่สามารถบอกได้ว่าผู้โทรเหล่านี้หมายถึงการส่งผ่านใดเนื่องจากไม่มีวิธีระบุว่าข้อที่สอง อาร์กิวเมนต์หมายถึงอาร์กิวเมนต์ที่สองหรืออาร์กิวเมนต์ที่สองถูกละไว้ดังนั้นสิ่งที่อยู่ในจุดของอาร์กิวเมนต์ที่สองจึงเป็นอาร์กิวเมนต์ที่สาม:
obj.query("firstArg", "secondArg");
obj.query("firstArg", "thirdArg");
เนื่องจากอาร์กิวเมนต์ทั้งสามเป็นประเภทเดียวกันคุณจึงไม่สามารถบอกความแตกต่างระหว่างอาร์กิวเมนต์ที่แตกต่างกันได้ดังนั้นคุณจึงไม่รู้ว่าผู้เรียกต้องการอะไร ด้วยรูปแบบการโทรนี้สามารถเลือกได้เฉพาะอาร์กิวเมนต์ที่สามเท่านั้น หากคุณต้องการเว้นอาร์กิวเมนต์ที่สองจะต้องส่งผ่านเป็นnull(หรือค่าอื่นที่ตรวจพบได้) แทนและโค้ดของคุณจะตรวจพบว่า:
obj.query("firstArg", null, "thirdArg");
นี่คือตัวอย่าง jQuery ของอาร์กิวเมนต์ที่เป็นทางเลือก อาร์กิวเมนต์ทั้งสองเป็นทางเลือกและรับค่าเริ่มต้นหากไม่ผ่าน:
clone: function( dataAndEvents, deepDataAndEvents ) {
dataAndEvents = dataAndEvents == null ? false : dataAndEvents;
deepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents;
return this.map( function () {
return jQuery.clone( this, dataAndEvents, deepDataAndEvents );
});
},
นี่คือตัวอย่าง jQuery ที่อาร์กิวเมนต์สามารถหายไปหรือประเภทใดประเภทหนึ่งจากสามประเภทที่แตกต่างกันซึ่งทำให้คุณมีโอเวอร์โหลดที่แตกต่างกันสี่แบบ:
html: function( value ) {
if ( value === undefined ) {
return this[0] && this[0].nodeType === 1 ?
this[0].innerHTML.replace(rinlinejQuery, "") :
null;
// See if we can take a shortcut and just use innerHTML
} else if ( typeof value === "string" && !rnoInnerhtml.test( value ) &&
(jQuery.support.leadingWhitespace || !rleadingWhitespace.test( value )) &&
!wrapMap[ (rtagName.exec( value ) || ["", ""])[1].toLowerCase() ] ) {
value = value.replace(rxhtmlTag, "<$1></$2>");
try {
for ( var i = 0, l = this.length; i < l; i++ ) {
// Remove element nodes and prevent memory leaks
if ( this[i].nodeType === 1 ) {
jQuery.cleanData( this[i].getElementsByTagName("*") );
this[i].innerHTML = value;
}
}
// If using innerHTML throws an exception, use the fallback method
} catch(e) {
this.empty().append( value );
}
} else if ( jQuery.isFunction( value ) ) {
this.each(function(i){
var self = jQuery( this );
self.html( value.call(this, i, self.html()) );
});
} else {
this.empty().append( value );
}
return this;
},
อาร์กิวเมนต์ที่มีชื่อ
ภาษาอื่น ๆ (เช่น Python) อนุญาตให้ส่งอาร์กิวเมนต์ที่มีชื่อเป็นวิธีการส่งผ่านอาร์กิวเมนต์บางส่วนเท่านั้นและทำให้อาร์กิวเมนต์ไม่ขึ้นอยู่กับลำดับที่ส่งผ่าน Javascript ไม่สนับสนุนคุณลักษณะของอาร์กิวเมนต์ที่ระบุชื่อโดยตรง รูปแบบการออกแบบที่ใช้กันทั่วไปคือการส่งผ่านแผนที่คุณสมบัติ / ค่า ซึ่งสามารถทำได้โดยการส่งผ่านวัตถุที่มีคุณสมบัติและค่าหรือใน ES6 ขึ้นไปคุณสามารถส่งผ่านวัตถุแผนที่ได้
นี่คือตัวอย่าง ES5 ง่ายๆ:
jQuery's $.ajax()ยอมรับรูปแบบการใช้งานที่คุณส่งผ่านพารามิเตอร์เดียวซึ่งเป็นวัตถุ Javascript ปกติที่มีคุณสมบัติและค่า คุณสมบัติใดที่คุณส่งผ่านเป็นตัวกำหนดว่าอาร์กิวเมนต์ / ตัวเลือกใดที่จะถูกส่งผ่านไปยังการเรียก ajax บางอย่างอาจจำเป็นหลายอย่างเป็นทางเลือก เนื่องจากเป็นคุณสมบัติของวัตถุจึงไม่มีคำสั่งเฉพาะ ในความเป็นจริงมีคุณสมบัติที่แตกต่างกันมากกว่า 30 คุณสมบัติที่สามารถส่งผ่านไปยังวัตถุนั้นได้โดยต้องมีเพียงหนึ่ง (url) เท่านั้น
นี่คือตัวอย่าง:
$.ajax({url: "http://www.example.com/somepath", data: myArgs, dataType: "json"}).then(function(result) {
// process result here
});
ภายใน$.ajax()การนำไปใช้งานจากนั้นสามารถซักถามคุณสมบัติที่ส่งผ่านไปยังวัตถุขาเข้าและใช้เป็นอาร์กิวเมนต์ที่ตั้งชื่อ สิ่งนี้สามารถทำได้ทั้งด้วยfor (prop in obj)หรือโดยการรับคุณสมบัติทั้งหมดลงในอาร์เรย์โดยใช้อาร์เรย์Object.keys(obj)นั้นซ้ำ
เทคนิคนี้ใช้กันมากใน Javascript เมื่อมีอาร์กิวเมนต์จำนวนมากและ / หรืออาร์กิวเมนต์จำนวนมากเป็นทางเลือก หมายเหตุ: สิ่งนี้ให้ความสำคัญกับฟังก์ชันการนำไปใช้งานเพื่อให้แน่ใจว่ามีชุดอาร์กิวเมนต์ที่ถูกต้องน้อยที่สุดอยู่และเพื่อให้ข้อเสนอแนะในการแก้ไขข้อบกพร่องบางอย่างแก่ผู้โทรถึงสิ่งที่ขาดหายไปหากส่งผ่านอาร์กิวเมนต์ไม่เพียงพอ .
ในสภาพแวดล้อม ES6 สามารถใช้การทำลายโครงสร้างเพื่อสร้างคุณสมบัติ / ค่าเริ่มต้นสำหรับอ็อบเจ็กต์ที่ส่งผ่านข้างต้น นี้จะกล่าวถึงในรายละเอียดในบทความนี้อ้างอิง
นี่คือตัวอย่างหนึ่งจากบทความนั้น:
function selectEntries({ start=0, end=-1, step=1 } = {}) {
···
};
คุณสมบัตินี้จะสร้างการเริ่มต้นและค่าสำหรับstart, endและstepคุณสมบัติในวัตถุที่ส่งผ่านไปยังselectEntries()ฟังก์ชั่น
ค่าดีฟอลต์สำหรับอาร์กิวเมนต์ของฟังก์ชัน
ใน ES6 Javascript จะเพิ่มการรองรับภาษาในตัวสำหรับค่าเริ่มต้นสำหรับอาร์กิวเมนต์
ตัวอย่างเช่น:
function multiply(a, b = 1) {
return a*b;
}
multiply(5); // 5
รายละเอียดเพิ่มเติมของวิธีการนี้สามารถนำมาใช้ที่นี่ใน MDN