2012-02-01 13 views
6

इससे पहले कि मैं कुछ बेकार कोशिश करने के लिए चिल्लाया जाए, मैं आपको बता दूं कि मैं वास्तविक जीवन में ऐसा नहीं करूँगा और यह एक अकादमिक प्रश्न है।किसी त्रुटि से पुन: प्रारंभ करें

मान लीजिए कि मैं एक पुस्तकालय लिख रहा हूं और मैं चाहता हूं कि मेरी वस्तु आवश्यकतानुसार विधियों को बनाने में सक्षम हो।

उदाहरण के लिए यदि आप एक .slice() विधि कॉल करना चाहता था, और मैं नहीं था एक तो window.onerror हैंडलर के लिए मुझे

यह निकाल देते थे, तो वैसे भी मैं इस here

window.onerror = function(e) { 
    var method = /'(.*)'$/.exec(e)[1]; 
    console.log(method); // slice 
    return Array.prototype[method].call(this, arguments); // not even almost gonna work 
}; 

var myLib = function(a, b, c) { 
    if (this == window) return new myLib(a, b, c); 
    this[1] = a; this[2] = b; this[3] = c; 
    return this; 
}; 

var obj = myLib(1,2,3); 

console.log(obj.slice(1)); 

इसके अलावा के साथ चारों ओर खेला (शायद मुझे एक नया सवाल शुरू करना चाहिए) क्या मैं अपने कन्स्ट्रक्टर को एक अनिर्दिष्ट राशि लेने के लिए बदल सकता हूं?

var myLib = function(a, b, c) { 
    if (this == window) return new myLib.apply(/* what goes here? */, arguments); 
    this[1] = a; this[2] = b; this[3] = c; 
    return this; 
}; 

BTW मैं जानता हूँ कि मैं

['slice', 'push', '...'].forEach(function() { myLib.prototype[this] = [][this]; }); 

के साथ मेरी वस्तुओं लोड कर सकते हैं यही कारण है कि मैं

+0

यह लग रहा है जैसे आप [ "pollyfills" या "की परतें"] (http://remysharp.com/2010/10/08/what-is-a-polyfill/) –

+1

संयोग से जावास्क्रिप्ट बारे में सोच रहे कोशिश-पकड़ ब्लॉक के साथ अपवादों को पकड़ने के लिए यह आमतौर पर अधिक सुरुचिपूर्ण और भरोसेमंद होता है। –

उत्तर

4

तलाश कर रहा हूँ नहीं कर रहा है आप एक शैक्षिक सवाल पूछ रहे थे के रूप में, मुझे लगता है कि ब्राउज़र संगतता एक नहीं है मुद्दा। यदि यह वास्तव में नहीं है, तो मैं इसके लिए सद्भावना प्रॉक्सी शुरू करना चाहता हूं। onerror बहुत अच्छा अभ्यास नहीं है क्योंकि यह केवल एक घटना है यदि कहीं कोई त्रुटि उत्पन्न होती है। इसे, यदि कभी, केवल अंतिम उपाय के रूप में उपयोग किया जाना चाहिए। (मुझे पता है कि आपने कहा है कि आप इसे किसी भी तरह से उपयोग नहीं करते हैं, लेकिन onerror सिर्फ डेवलपर-अनुकूल नहीं है।)

असल में, प्रॉक्सी आपको जावास्क्रिप्ट में अधिकांश मौलिक संचालन को रोकने में सक्षम बनाता है - सबसे विशेष रूप से कोई भी संपत्ति जो प्राप्त हो रही है यहां उपयोगी इस मामले में, आप .slice प्राप्त करने की प्रक्रिया को रोक सकते हैं।

ध्यान दें कि प्रॉक्सी डिफ़ॉल्ट रूप से "ब्लैक होल" हैं। वे किसी ऑब्जेक्ट से मेल नहीं खाते हैं (उदाहरण के लिए प्रॉक्सी पर एक संपत्ति सेट करना सिर्फ set जाल (इंटरसेप्टर) को कॉल करता है; वास्तविक भंडारण आपको स्वयं करना है)। लेकिन एक "फॉरवर्डिंग हैंडलर" उपलब्ध है जो सबकुछ सामान्य वस्तु (या पाठ्यक्रम का उदाहरण) के माध्यम से करता है, ताकि प्रॉक्सी सामान्य वस्तु के रूप में व्यवहार करे। हैंडलर को विस्तारित करके (इस मामले में, get भाग), आप निम्नानुसार Array.prototype विधियों को आसानी से रूट कर सकते हैं।

तो, जब भी किसी भी संपत्ति (नाम name के साथ) प्राप्त किए गए किया जा रहा है, कोड पथ इस प्रकार है:

  1. inst[name] लौटने का प्रयास करें।
  2. अन्यथा, इस फ़ंक्शन को दिए गए तर्कों के साथ उदाहरण पर Array.prototype[name] लागू करने वाले फ़ंक्शन को वापस करने का प्रयास करें।
  3. अन्यथा, बस undefined वापस करें।

आप प्रॉक्सी के साथ चारों ओर खेलने के लिए चाहते हैं, आप क्रोमियम का एक रात का निर्माण में उदाहरण के लिए वी 8 का नवीनतम संस्करण, उपयोग कर सकते हैं (chrome --js-flags="--harmony" के रूप में चलाने के लिए सुनिश्चित कर लें)। दोबारा, प्रॉक्सी "सामान्य" उपयोग के लिए उपलब्ध नहीं हैं क्योंकि वे अपेक्षाकृत नए हैं, जावास्क्रिप्ट के बहुत से मौलिक हिस्सों को बदलते हैं और वास्तव में आधिकारिक तौर पर अभी तक निर्दिष्ट नहीं हैं (अभी भी ड्राफ्ट)।

यह एक सरल चित्र है कि यह कैसा चल रहा है (inst वास्तव में प्रॉक्सी है जिसे उदाहरण में लपेटा गया है)। ध्यान दें कि यह केवल को संपत्ति को चित्रित करता है; असम्बद्ध अग्रेषण हैंडलर की वजह से अन्य सभी परिचालनों को प्रॉक्सी द्वारा पारित किया जाता है।

proxy diagram

प्रॉक्सी कोड इस प्रकार हो सकता है:

function Test(a, b, c) { 
    this[0] = a; 
    this[1] = b; 
    this[2] = c; 

    this.length = 3; // needed for .slice to work 
} 

Test.prototype.foo = "bar"; 

Test = (function(old) { // replace function with another function 
         // that returns an interceptor proxy instead 
         // of the actual instance 
    return function() { 
    var bind = Function.prototype.bind, 
     slice = Array.prototype.slice, 

     args = slice.call(arguments), 

     // to pass all arguments along with a new call: 
     inst = new(bind.apply(old, [null].concat(args))), 
     //      ^is ignored because of `new` 
     //       which forces `this` 

     handler = new Proxy.Handler(inst); // create a forwarding handler 
              // for the instance 

    handler.get = function(receiver, name) { // overwrite `get` handler 
     if(name in inst) { // just return a property on the instance 
     return inst[name]; 
     } 

     if(name in Array.prototype) { // otherwise try returning a function 
            // that calls the appropriate method 
            // on the instance 
     return function() { 
      return Array.prototype[name].apply(inst, arguments); 
     }; 
     } 
    }; 

    return Proxy.create(handler, Test.prototype); 
    }; 
})(Test); 

var test = new Test(123, 456, 789), 
    sliced = test.slice(1); 

console.log(sliced);    // [456, 789] 
console.log("2" in test);   // true 
console.log("2" in sliced);  // false 
console.log(test instanceof Test); // true 
            // (due to second argument to Proxy.create) 
console.log(test.foo);    // "bar" 

अग्रेषण हैंडलर the official harmony wiki पर उपलब्ध है।

Proxy.Handler = function(target) { 
    this.target = target; 
}; 

Proxy.Handler.prototype = { 
    // Object.getOwnPropertyDescriptor(proxy, name) -> pd | undefined 
    getOwnPropertyDescriptor: function(name) { 
    var desc = Object.getOwnPropertyDescriptor(this.target, name); 
    if (desc !== undefined) { desc.configurable = true; } 
    return desc; 
    }, 

    // Object.getPropertyDescriptor(proxy, name) -> pd | undefined 
    getPropertyDescriptor: function(name) { 
    var desc = Object.getPropertyDescriptor(this.target, name); 
    if (desc !== undefined) { desc.configurable = true; } 
    return desc; 
    }, 

    // Object.getOwnPropertyNames(proxy) -> [ string ] 
    getOwnPropertyNames: function() { 
    return Object.getOwnPropertyNames(this.target); 
    }, 

    // Object.getPropertyNames(proxy) -> [ string ] 
    getPropertyNames: function() { 
    return Object.getPropertyNames(this.target); 
    }, 

    // Object.defineProperty(proxy, name, pd) -> undefined 
    defineProperty: function(name, desc) { 
    return Object.defineProperty(this.target, name, desc); 
    }, 

    // delete proxy[name] -> boolean 
    delete: function(name) { return delete this.target[name]; }, 

    // Object.{freeze|seal|preventExtensions}(proxy) -> proxy 
    fix: function() { 
    // As long as target is not frozen, the proxy won't allow itself to be fixed 
    if (!Object.isFrozen(this.target)) { 
     return undefined; 
    } 
    var props = {}; 
    Object.getOwnPropertyNames(this.target).forEach(function(name) { 
     props[name] = Object.getOwnPropertyDescriptor(this.target, name); 
    }.bind(this)); 
    return props; 
    }, 

    // == derived traps == 

    // name in proxy -> boolean 
    has: function(name) { return name in this.target; }, 

    // ({}).hasOwnProperty.call(proxy, name) -> boolean 
    hasOwn: function(name) { return ({}).hasOwnProperty.call(this.target, name); }, 

    // proxy[name] -> any 
    get: function(receiver, name) { return this.target[name]; }, 

    // proxy[name] = value 
    set: function(receiver, name, value) { 
    this.target[name] = value; 
    return true; 
    }, 

    // for (var name in proxy) { ... } 
    enumerate: function() { 
    var result = []; 
    for (var name in this.target) { result.push(name); }; 
    return result; 
    }, 

    // Object.keys(proxy) -> [ string ] 
    keys: function() { return Object.keys(this.target); } 
}; 
संबंधित मुद्दे