100 JS hattında Dinamik Polimorfizm ile Fonksiyon Aşırı Yüklemesi
Buna, daha geniş bir kod gövdeden olup isFn
, isArr
vb tip kontrol fonksiyonları. Aşağıdaki VanillaJS sürümü, tüm harici bağımlılıkları kaldırmak için elden geçirildi, ancak .add()
aramalarda kullanmak için kendi tür kontrol işlevlerinizi tanımlamanız gerekecek .
Not: Bu kendi kendini yürüten bir işlevdir (bu nedenle bir kapatma / kapalı kapsamımız olabilir), dolayısıyla atama window.overload
yerine 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;
}();
Kullanımı:
Arayan, aşırı yüklenmiş işlevlerini, dönüşüne bir değişken atayarak tanımlar overload()
. Zincirleme sayesinde, ek aşırı yükler seri olarak tanımlanabilir:
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()
İmza tanımlanamazsa çağrılacak "varsayılan" işlevi tanımlamak için isteğe bağlı tek bağımsız değişken . Argümanları .add()
:
fn
: function
aşırı yükün tanımlanması;
a_vArgumentTests
: Array
Ait function
testleri tanımlayan s çalıştırmak için arguments
. Her biri function
tek bir argümanı kabul eder ve geri dönertrue
ve argümanın geçerli olup olmadığına bağlı olarak ;
sAlias
(İsteğe bağlı): string
takma adın aşırı yük fonksiyonuna doğrudan erişmek için tanımlanması ( fn
), örneğin myOverloadedFn.noArgs()
argümanların dinamik polimorfizm testlerinden kaçınarak bu fonksiyonu doğrudan çağıracaktır.
Bu uygulama aslında ikinci a_vArgumentTests
argüman olarak geleneksel fonksiyon aşırı yüklemelerinden daha fazlasına izin verir ..add()
özel türleri tanımladığından, . Böylece, argümanları yalnızca türe değil, aralıklara, değerlere veya değer koleksiyonlarına da dayanarak geçebilirsiniz!
145 kod satırına bakarsanız overload()
, her imzanın kendisine arguments
geçirilen sayıyla kategorize edildiğini görürsünüz . Bu, yaptığımız test sayısını sınırlamak için yapılır. Ayrıca bir çağrı sayısını takip ediyorum. Bazı ek kodlarda, aşırı yüklenmiş fonksiyonların dizileri yeniden sıralanabilir, böylece daha yaygın olarak adlandırılan fonksiyonlar ilk önce test edilir ve yine bir miktar performans artışı ölçüsü eklenir.
Şimdi, bazı uyarılar var ... Javascript gevşek yazıldığından, vArgumentTests
bir integer
olarak doğrulanabileceğinden,float
, vb
JSCompress.com sürümü (1114 bayt, 744 bayt g-sıkıştırılmış):
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}();