फंक्शन कंस्ट्रक्टर के साथ Object.prototype विधि को ओवरराइड करते समय सीमा त्रुटि

Nov 30 2020

मैं Object.prototype.toStringअतिरिक्त वर्ग विवरण के लिए कार्यक्षमता जोड़ने के लिए बोली में ओवरराइड करने की कोशिश कर रहा हूं ।

यहाँ प्रारंभिक कोड है:

(function(toString){
    Object.prototype.toString = function(){
        if(this instanceof TestClass)
        {
            return '[object TestClass]';
        }
        return toString.apply(this, arguments);
    }
})(Object.prototype.toString);

function TestClass(){}
var instance_obj = new TestClass();
Object.prototype.toString.call(instance_obj);

जब मैं इसे कंसोल में चलाता हूं, तो मुझे निम्न आउटपुट मिलते हैं:

[object TestClass]

अच्छी बात यह है कि यह काम करने के तरीके में बहुत अधिक बदलाव नहीं Object.prototype.toStringकरता है, इसलिए एक अन्य प्रकार [यानी टेस्टक्लास नहीं] के साथ, चीजें उसी तरह काम करती हैं जैसे कि अपेक्षित Object.prototype.toString.call(12)आउटपुट होगा [object Number]

यह कार्यान्वयन अब तक कोई समस्या नहीं है। हालाँकि, निम्नलिखित कोड के साथ मेरा एक और कार्यान्वयन है:

(function(toString){
    var fn_code_str = `return function(){
        if(this instanceof TestClass)
        {
            return '[object TestClass]';
        }
            
        return toString.apply(this, arguments);
    }`;
    var pre_fn = new Function(fn_code_str);
    Object.prototype.toString = pre_fn();
})(Object.prototype.toString);

function TestClass(){}
var instance_obj = new TestClass();
Object.prototype.toString.call(instance_obj);

इसके साथ, मुझे TestClass के लिए उचित आउटपुट मिलता है, लेकिन जब मैं किसी और चीज का उपयोग करता हूं, जैसे 12, मुझे एक RangeError मिलता है:

VM527:5 Uncaught RangeError: Maximum call stack size exceeded
    at Function.[Symbol.hasInstance] (<anonymous>)
    at Number.eval (eval at <anonymous> (getElements.html:19), <anonymous>:5:21)
    at Number.eval (eval at <anonymous> (getElements.html:19), <anonymous>:10:29)
    at Number.eval (eval at <anonymous> (getElements.html:19), <anonymous>:10:29)
    at Number.eval (eval at <anonymous> (getElements.html:19), <anonymous>:10:29)
    at Number.eval (eval at <anonymous> (getElements.html:19), <anonymous>:10:29)
    at Number.eval (eval at <anonymous> (getElements.html:19), <anonymous>:10:29)
    at Number.eval (eval at <anonymous> (getElements.html:19), <anonymous>:10:29)
    at Number.eval (eval at <anonymous> (getElements.html:19), <anonymous>:10:29)
    at Number.eval (eval at <anonymous> (getElements.html:19), <anonymous>:10:29)

यह पुनरावृत्ति के साथ एक मुद्दा प्रतीत होता है toString.apply। हालाँकि, मैं यह पता नहीं लगा सकता कि यह दूसरा कार्यान्वयन क्यों घट रहा है, अगर पहले वाला नहीं होता है?

नोट : इस दूसरे कार्यान्वयन का कारण if(this instanceof MyClassType){return '[object MyClassType]'}विभिन्न प्रकार के वर्गों के लिए टाइपिंग-चेकिंग कोड [यानी ] को श्रेणी के नामों की सूची से गतिशील रूप से जोड़ना है । दूसरे शब्दों में, मैं जिस नई कक्षा के साथ आता हूं उसके लिए कोड को संशोधित करने के बजाय, मैं वर्ग नाम को इसके बजाय सरणी में जोड़ता हूं, और सशर्त विवरण स्वचालित रूप से उत्पन्न होता है।

जवाब

3 Bergi Nov 30 2020 at 15:42

समस्या यह है कि toStringआपके IIFE का पैरामीटर आपके new Functionकोड में दायरे में नहीं है । इसके बजाय, यह वैश्विक toString= window.toString= का उपयोग करता है Object.prototype.toString

इसे ठीक करने के लिए, आपको रिटर्न को बंद करने के काम के लिए toStringचर के अंदर चर घोषित करने की आवश्यकता है new Function। या तो एक साधारण स्थिरांक के रूप में:

(function() {
    var pre_fn = new Function(`
    const toString = Object.prototype.toString;
//  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    return function(){
        if(this instanceof TestClass) {
            return '[object TestClass]';
        }
            
        return toString.apply(this, arguments);
    }`);
    Object.prototype.toString = pre_fn();
})();

या एक पैरामीटर के रूप में:

(function() {
    var pre_fn = new Function('toString', `
//                            ^^^^^^^^^^^
    return function(){
        if(this instanceof TestClass) {
            return '[object TestClass]';
        }
            
        return toString.apply(this, arguments);
    }`);
    Object.prototype.toString = pre_fn(Object.prototype.toString);
//                                     ^^^^^^^^^^^^^^^^^^^^^^^^^
})();