2011-09-06 13 views
6

के विचार करें मैं निम्नलिखित कोडरैपिंग कार्य करता है और function.length

/*...*/ 
var _fun = fun; 
fun = function() { 
    /*...*/ 
    _fun.apply(this, arguments); 
} 

है मैं सिर्फ _fun पर .length डेटा खो दिया है क्योंकि मैं कुछ अवरोधन तर्क के साथ लपेट करने की कोशिश की हैं। इस प्रकार

Object.defineProperty(fun, "length", { 
    value: /*...*/, 
    writable: false, 
    configurable: false, 
    enumerable: false 
} 

यह देखते हुए कि fun अंदर तर्क .length की आवश्यकता है सही होने की

निम्नलिखित

var f = function(a,b) { }; 
console.log(f.length); // 2 
f.length = 4; 
console.log(f.length); // 2 

काम नहीं करता है .length परिभाषित किया गया है annotated ES5.1 specification states कि, मैं कैसे रोकना और अधिलेखित कर सकते हैं .length डेटा को नष्ट किए बिना यह कार्य?

मुझे एहसास है कि मुझे eval और डोडी Function.prototype.toString का उपयोग करने की आवश्यकता होगी ताकि तर्कों की एक ही संख्या के साथ एक नई स्ट्रिंग का निर्माण किया जा सके। मैं इससे बचना चाहता हूं।

+0

आपको वास्तव में ठीक से सेट करने के लिए 'लंबाई' की आवश्यकता है? आप https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Function/bind पर एक नज़र डालना चाहते हैं, कई पुस्तकालय भी इस व्यवहार को अनुकरण करते हैं। – Prusse

+0

@Prusse मेरी समस्या को ठीक करने के लिए बाध्य कैसे है? – Raynos

+0

केवल एक सुझाव, स्पष्ट रूप से आपके उद्देश्य को समझ नहीं सकता, क्षमा करें। – Prusse

उत्तर

3

मुझे पता है कि आप किसी अन्य तरीके से पसंद करेंगे, लेकिन मैं सोच सकता हूं कि Function कन्स्ट्रक्टर के साथ कुछ एक साथ हैक करना है। गंदा, कम से कम कहने के लिए है, लेकिन यह काम करने के लिए लगता है:

var replaceFn = (function(){ 
    var args = 'abcdefghijklmnopqrstuvwxyz'.split(''); 
    return function replaceFn(oldFn, newFn) { 
     var argSig = args.slice(0, oldFn.length).join(','); 
     return Function(
      'argSig, newFn', 
      'return function(' 
       + argSig + 
      '){return newFn.apply(this, arguments)}' 
     )(argSig, newFn); 
    }; 
}()); 

// Usage: 
var _fun = fun; 

fun = replaceFn(fun, function() { 
    /* ... */ 
    _fun.apply(this, arguments); 
}); 
+0

गन्दा, लेकिन अभी भी अच्छा :) –

2

Faking लंबाई सही ढंग से और लगातार जावास्क्रिप्ट में अंतिम सीमा है और वह काफी शुरुआत और इसका अंत है। ऐसी भाषा में जहां आप सब कुछ के बारे में नकली कर सकते हैं, लंबाई अभी भी कुछ हद तक जादुई है। ईएस 6 वितरित करेगा, और हम अब और अधिक डिग्री के लिए नकली कर सकते हैं कि आप किस इंजन और संस्करण में हैं। सामान्य वेब संगतता के लिए यह एक तरीका है। कुछ समय के लिए प्रॉक्सी/noSuchMethod मोज़िला में रहा है। प्रॉक्सी और वीकमैप्स क्रोमियम में वी 8 में उपयोग करने योग्य हैं और नोड (सक्षम करने के लिए झंडे की आवश्यकता है) जो आपको नकली लंबाई के लिए आवश्यक उपकरण प्रदान करते हैं।

"लंबाई" पर विस्तार में: http://perfectionkills.com/how-ecmascript-5-still-does-not-allow-to-subclass-an-array/

अंतिम समाधान: http://wiki.ecmascript.org/doku.php?id=harmony:proxies + http://wiki.ecmascript.org/doku.php?id=harmony:weak_maps

+0

क्या आप समझा सकते हैं कि कैसे प्रॉक्सी नकली लंबाई में मदद कर सकता है। और कैसे कमजोर नक्शे संभवतः मदद कर सकते हैं? इसके अलावा आप "लंबाई" के संदर्भ में – Raynos

+0

कार्य करने के लिए अरणों को संदर्भित करते हैं, प्रॉक्सी के साथ आप इंडेक्स के लिए एक कैचल गेटर बना सकते हैं और देशी लंबाई की संपत्ति से मेल खाने के लिए सभी आवश्यक व्यवहार को दोहरा सकते हैं। WeakMaps वे हैं जो आप गैर-मौजूद गुणों के लिए एक्सेसर्स प्रदान करने के लिए उपयोग करेंगे जो प्रकार/अपरिभाषित चेक किए जाने से पहले प्रॉक्सी स्नैग किए जाते हैं। जब आप अपने नकली सरणी पर 401042 के लिए गेटर तक पहुंचने के लिए कुछ करते हैं तो आप पहले उस संपत्ति को वीकैप का उपयोग करके परिभाषित करते हैं और फिर अपनी नकली लंबाई संपत्ति का मूल्य बदलते हैं। सभी मूल लंबाई गुण जावाScripts दायरे के बाहर एक वास्तविक डेटा संरचना के आंतरिक संकेतक हैं और इस प्रकार "जादुई" व्यवहार दिखा सकते हैं। –

+0

फ़ंक्शंस पर लम्बाई लम्बाई एरेज़ की तुलना में कम उपयोगी है लेकिन यह अभी भी जादुई रूप से प्रभावित है, और इस मामले में यह ब्राउज़र के बीच अप्रत्याशित रूप से व्यवहार करता है। मोज़िला आकार बदलता है और स्पष्ट रूप से मैंने कुछ और नहीं देखा है। V8 आपके द्वारा सेट किए जाने वाले नंबर को वापस लौटाता है, लेकिन वास्तव में मान को नहीं बदलता है और आप जो भी करते हैं, उसके बावजूद पैरामीटर की वास्तविक संख्या वापस कर देंगे। लंबाई को जो कुछ भी दर्शाता है उसे याद रखने के लिए लंबाई को प्रत्यक्ष मैपिंग माना जाता है। –

2

मैं इस उद्देश्य के लिए निम्नलिखित समारोह का उपयोग करें; उचित पैरामीटर गणना वाले कार्यों के लिए यह वास्तव में तेज़ है, स्वीकृत उत्तर से अधिक लचीला और 26 से अधिक पैरामीटर वाले कार्यों के लिए काम करता है।

function fakeFunctionLength(fn, length) { 
    var fns = [ 
     function() { return fn.apply(this, arguments); }, 
     function (a) { return fn.apply(this, arguments); }, 
     function (a, b) { return fn.apply(this, arguments); }, 
     function (a, b, c) { return fn.apply(this, arguments); }, 
     function (a, b, c, d) { return fn.apply(this, arguments); }, 
     function (a, b, c, d, e) { return fn.apply(this, arguments); }, 
     function (a, b, c, d, e, f) { return fn.apply(this, arguments); } 
    ], argstring; 

    if (length < fns.length) { 
     return fns[length]; 
    } 

    argstring = ''; 
    while (--length) { 
     argstring += ',_' + length; 
    } 
    return new Function('fn', 
     'return function (_' + argstring + ') {' + 
      'return fn.apply(this, arguments);' + 
     '};')(fn); 
} 
0

आप केवल eval/Function मार्ग नीचे जाने के लिए अगर आप मापदंडों के किसी भी संख्या के साथ कार्य का समर्थन करने की जरूरत है की जरूरत है। आप एक उचित ऊपरी सीमा (मेरे उदाहरण 5) निर्धारित कर सकते हैं, तो तो आप निम्न कर सकते हैं:

var wrapFunction = function(func, code, where){ 
    var f; 
    switch (where) { 
    case 'after': 
     f = function(t,a,r){ r = func.apply(t,a); code.apply(t,a); return r; } 
    break; 
    case 'around': 
     f = function(t,a){ return code.call(t,func,a); } 
    break; 
    default: 
    case 'before': 
     f = function(t,a){ code.apply(t,a); return func.apply(t,a); } 
    break; 
    } 
    switch (func.length) { 
    case 0: return function(){return f(this, arguments);}; break; 
    case 1: return function(a){return f(this, arguments);}; break; 
    case 2: return function(a,b){return f(this, arguments);}; break; 
    case 3: return function(a,b,c){return f(this, arguments);}; break; 
    case 4: return function(a,b,c,d){return f(this, arguments);}; break; 
    case 5: return function(a,b,c,d,e){return f(this, arguments);}; break; 
    default: 
     console.warn('Too many arguments to wrap successfully.'); 
    break; 
    } 
} 

कोड लपेटकर का यह तरीका भी अलग where स्विच बनाने के द्वारा बढ़ाई है। मैंने before और after लागू किया है क्योंकि वे मेरे स्वयं के प्रोजेक्ट — और around के लिए सबसे उपयोगी हैं क्योंकि यह मुझे लिस्प की याद दिलाता है। इस सेट-अप का उपयोग करके आप रैपिंग (var f) को बाहरी कोड पर भी बंद कर सकते हैं ताकि आप where कीवर्ड के लिए सिस्टम जैसे प्लगइन विकसित कर सकें, जिसका अर्थ है कि आप wrapFunction समर्थित आसानी से विस्तार या ओवरराइड कर सकते हैं।

स्पष्ट रूप से आप बदल सकते हैं कि कोड वास्तव में कैसे लपेटा जाता है, हालांकि आप वास्तव में स्ट्रिंग बनाने और new Function पर जाने के बारे में चिंता किए बिना 999 और एड्रियनलैंग के समान तकनीक का उपयोग कर रहे हैं।

संबंधित मुद्दे