ฟังก์ชั่นโอเวอร์โหลดผ่าน Dynamic Polymorphism ใน 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()
คือ:
fn
: function
การกำหนดเกินพิกัด;
a_vArgumentTests
: Array
ของfunction
s arguments
กำหนดทดสอบการทำงานบน แต่ละคนfunction
ยอมรับอาร์กิวเมนต์เดียวและคืนค่าของคุณtrue
ตามหากการโต้แย้งนั้นถูกต้อง
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}();