जे एस के 100 लाइनों में गतिशील बहुरूपता के माध्यम से समारोह ओवरलोडिंग
इस कोड का एक बड़ा शरीर जिसमें शामिल है से है isFn
, isArr
आदि प्रकार की जाँच के काम करता है। नीचे दिए गए वनीलाजेएस संस्करण को सभी बाहरी निर्भरता को दूर करने के लिए फिर से काम किया गया है, हालांकि आपको .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
परीक्षण को परिभाषित रों पर चलने के लिए arguments
। यदि कोई तर्क मान्य है, तो प्रत्येक function
एक तर्क को स्वीकार करता है और true
आपके आधार को लौटाता है;
sAlias
(वैकल्पिक): string
ओवरलोड फ़ंक्शन को सीधे एक्सेस करने के लिए उपनाम को परिभाषित करना ( fn
), उदाहरण myOverloadedFn.noArgs()
के लिए तर्कों के गतिशील बहुरूपता परीक्षणों से बचते हुए, सीधे उस फ़ंक्शन को कॉल करेगा।
यह कार्यान्वयन वास्तव में पारंपरिक फ़ंक्शन को ओवरलोड से अधिक के लिए अनुमति देता है क्योंकि अभ्यास में दूसरा a_vArgumentTests
तर्क .add()
कस्टम प्रकारों को परिभाषित करता है। इसलिए, आप न केवल प्रकार के आधार पर, बल्कि श्रेणियों, मूल्यों या मूल्यों के संग्रह पर भी तर्क दे सकते हैं!
यदि आप कोड की 145 पंक्तियों के माध्यम से overload()
देखते हैं , तो आप देखेंगे कि प्रत्येक हस्ताक्षर arguments
को उसमें पारित संख्या के आधार पर वर्गीकृत किया गया है। ऐसा इसलिए किया जाता है ताकि हम उन परीक्षणों की संख्या को सीमित कर रहे हैं जिन्हें हम चला रहे हैं। मैं एक कॉल काउंट पर भी नज़र रखता हूँ। कुछ अतिरिक्त कोड के साथ, ओवरलोड कार्यों के सरणियों को फिर से क्रमबद्ध किया जा सकता है ताकि अधिक सामान्यतः कार्यों को पहले परीक्षण किया जा सके, फिर से प्रदर्शन बढ़ाने के कुछ उपायों को जोड़ा जा सके।
अब, कुछ कैविएट हैं ... जैसा कि जावास्क्रिप्ट शिथिल टाइप किया जाता है, आपको अपने साथ सावधानी बरतनी होगी vArgumentTests
क्योंकि एक के integer
रूप में मान्य किया जा सकता है float
, आदि।
JSCompress.com संस्करण (1114 बाइट्स, 744 बाइट्स जी-ज़िप्ड):
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}();