2013-02-02 10 views
6

पहले जोड़े पैराग्राफ वर्णन करते हैं कि मैं क्या हासिल करने का प्रयास कर रहा हूं, वास्तविक प्रश्न अंत में है। धन्यवादऑब्जेक्ट-निर्माण फ़ंक्शन

पहले, मैं ऑब्जेक्ट बनाने के लिए new कीवर्ड का उपयोग कर रहा हूं, और विधियों को असाइन करने और विरासत को संभालने के लिए प्रोटोटाइप का उपयोग कर रहा हूं। हाल ही में, तथापि, (आंशिक रूप से CoffeeScript-उत्पन्न जे एस से प्रेरित) मैं एक वस्तु बनाने समारोह के साथ खेलने के लिए है कि कुछ इस तरह दिखाई होगा फैसला:

var Test = function(a) { 
    function Test(a) { 
     this.a = a; 
    } 
    var numCalls = 0; 
    Test.prototype.output = function() { 
     alert('I was initialized with ' + this.a); 
     numCalls++; 
    }; 
    Test.prototype.called = function() { 
     alert('You called the output ' + numCalls + ' times'); 
    }; 
    return new Test(a); 
}; 

मैं तो इस तरह की एक नई वस्तु बनाने होगा:

var obj = Test('string'); 

इस दृष्टिकोण के सामान्य दृष्टिकोण पर कुछ फायदे हैं जो प्रत्येक उदाहरण के लिए new का उपयोग करते हैं। सबसे पहले, मुझे new शब्द का उपयोग करना भूलने की बहुत कम संभावना है (मुझे पता है कि new से बचने के अन्य तरीके हैं, लेकिन मैंने जो देखा है उससे उन्हें नीचे वर्णित एक की समस्या है), और दूसरा, मैं आसानी से कर सकता हूं 'निजी' वेरिएबल देखें जो कन्स्ट्रक्टर किसी भी फ़ंक्शन में देखता है जो अब कक्षा का हिस्सा है। हालांकि परीक्षण करते समय मैंने एक चेतावनी में भाग लिया था। instanceof अब काम नहीं करता है क्योंकि यह आंतरिक-स्कोप्ड ऑब्जेक्ट टेस्ट नहीं देखता है। इसके आसपास काम करने के लिए, मैंने इसके बजाय कन्स्ट्रक्टर प्रॉपर्टी का उपयोग करने की कोशिश की:

var a = Test('one'); 
var b = Test('two'); 
a.constructor == b.constructor    // false 
a.constructor.name == b.constructor.name // true 

और यही मुझे उलझन में मिला। ऑब्जेक्ट-निर्माण फ़ंक्शन का उपयोग किये बिना वही ऑब्जेक्ट्स बनाना उनके कन्स्ट्रक्टर को बराबर बना देगा, लेकिन इस मामले में वे भिन्न हैं। मेरा अनुमान है कि क्या हो रहा है कि फ़ंक्शन चलाने पर हर बार एक नया ऑब्जेक्ट प्रकार उत्पन्न होता है (ऑब्जेक्ट संरचना समान होती है, लेकिन प्रोटोटाइप का उदाहरण अलग होता है)।

यदि समस्या की मेरी समझ सही है, तो इसका मतलब यह भी है कि कोड मेरे जावास्क्रिप्ट को प्रति क्रिया उदाहरण के लिए अतिरिक्त मेमोरी आवंटित कर रहा है जो कि उदाहरण के बीच साझा किया जाना चाहिए ताकि प्रत्येक उदाहरण के लिए एक समान ऑब्जेक्ट प्रोटोटाइप बनाया जा सके। (प्रोटोटाइप का उपयोग करने के पूरे उद्देश्य को हराकर)? यदि हां, तो क्या इस पैटर्न के लाभों को ध्यान में रखते हुए (आंतरिक कार्यों के बीच निजी चर साझा करने की क्षमता और new कीवर्ड का उपयोग न करने के दौरान) इस से बचने का कोई अच्छा तरीका है?

यदि मैं समस्या को गलत समझ रहा हूं, तो क्या कोई मुझे वास्तव में क्या हो रहा है पर प्रकाश डाल सकता है?

+0

आप कीवर्ड को नया क्यों भूल जाते हैं? मेरा मतलब है, हर बार जब आप एक नई वस्तु बनाते हैं, तो आप "नया" उपयोग करते हैं, यह बहुत आसान है। यह समाधान कई ओओ भाषाओं में दर्जनों वर्षों के लिए मौजूद है, और यह एक अच्छी बात है, क्योंकि हर कोई आपके कोड को पढ़ और समझ सकता है। जबकि कोई भी var obj = test ('string') को समझता नहीं है, आपका कोड कम पठनीय होगा। लेकिन यह कुछ जेएस प्रोग्रामर का अंतिम लक्ष्य है, मुझे पता है। ;) – Marcus

+0

@ मार्कस, जैसा कि बताया गया है, 'नया' कीवर्ड इस पैटर्न का एकमात्र लाभ नहीं है। इसके अलावा, मैं टीम पर एकमात्र प्रोग्रामर नहीं हूं। यह मानते हुए कि हर कोई हमेशा 'नए' कीवर्ड का उपयोग करना याद रखेगा, जबकि पायथन में बैक-एंड लिखना (जो वर्गों के लिए 'नया' उपयोग नहीं करता है) अवास्तविक है। प्रत्येक उदाहरण निर्माण की तुलना में कक्षा घोषणा के अंत में एक लापता 'नया' खोजना बहुत आसान है। –

+0

आह, मुझे अब मिल गया: प्रोग्रामर को यह कहने वाला कोई कंपाइलर नहीं है कि वह "नया" भूल गया, इसलिए आप इसका उपयोग नहीं करना चाहते हैं। – Marcus

उत्तर

3

यदि हां, तो वहाँ एक अच्छा तरीका अभी भी इस पैटर्न के लाभ रखते हुए इस जबकि से बचने के लिए है ...

बजाय एक मॉड्यूल दृष्टिकोण का उपयोग कर प्रयास करें:

var Test = (function TestModule() { 

    function Test(a) { 
    this.a = a; 
    } 

    Test.prototype = { 

    }; 

    return function(a) { 
    return new Test(a); 
    }; 

}()); 

var a = Test('foo'); 
var b = Test('baz'); 

a.constructor == b.constructor; // true 
a.constructor.name == b.constructor.name; // true 
+0

यह पहला क्या है '(' लाइन 'var test = (फ़ंक्शन टेस्ट मॉड्यूल() {'? में वास्तव में यह मतलब नहीं है कि मैं वास्तव में उस तरह का कोड समझ नहीं पा रहा हूं ... – Marcus

+0

@ मार्कस: यह एक आईआईएफई है। यहां एक नज़र डालें : //benalman.com/news/2010/11/immediately-invoked-function-expression/ – elclanrs

0

अब मैंने इसे पूरा करने के लिए कड़ी मेहनत की: पूर्ण encapsulation के साथ एकदम सही वर्ग और इसे "तुरंत" करने के लिए आवश्यक नहीं है।थोड़ी देर के खोज के बाद मैं इस के साथ आया था:

function Test(x){ 

    var innerFunction = function(y){ 
     var variable = y; 

     this.getA = function(){ 
      return variable; 
     } 

     this.setA = function(x){ 
      variable = x; 
     } 
    } 
    return new innerFunction(x); 
} 

लेकिन परीक्षण के परिणाम यह गलत साबित:

var a = Test("foo"); 
var b = Test("baz"); 

alert(a.constructor == b.constructor);    //false, not good! 
alert(a.constructor.name == b.constructor.name); //true 

तो वहाँ गलत गुंजाइश लग रहा था, तो मैं एक सार्वजनिक भीतरी फ़ंक्शन का उपयोग किया :

function Test(x){ 

    function innerFunction(y){ 
     var variable = y; 

     this.getA = function(){ 
      return variable; 
     } 

     this.setA = function(x){ 
      variable = x; 
     } 
    } 
    return new innerFunction(x); 
} 

और चल रहा है कुछ व्यापक परीक्षण साबित कर दिया कि वह सही है:

+०१२३५१६४१०६
var a = Test("foo"); 
var b = Test("baz"); 

alert(a.constructor == b.constructor);    //true, made it! 
alert(a.constructor.name == b.constructor.name); //true 

alert(a.getA());      //"foo" as expected 
alert(a.getA() == b.getA());   //false as expected 

a.variable = "whatever"; 
alert(a.getA());      //"foo" as expected 
alert(a.variable);      //"whatever", doesn't seem preventable 

a.setA("somewhere"); 
alert(a.getA());      //"somewhere", as expected 
alert(a.variable);      //"whatever", doesn't seem preventable 

लेकिन, क्या हम इस तरह से कई कार्यों का उपयोग कर सकते हैं? यह मेरा पहला दृष्टिकोण था:

function Test(x){ 

    function innerFunction(y){ 
     var variable = y; 

     this.getA = function(){ 
      return variable; 
     } 

     this.setA = function(x){ 
      variable = x; 
     } 
    } 
    return new innerFunction(x); 
} 

function TestToo(x){ 

    function innerFunction(y){ 
     var variable = y; 

     this.getA = function(){ 
      return variable; 
     } 

     this.setA = function(x){ 
      variable = x; 
     } 
    } 
    return new innerFunction(x); 
} 

var a = Test("foo"); 
var b = Test("baz"); 

var c = TestToo("foo"); 
var d = TestToo("baz"); 

alert(a.constructor == b.constructor);    //true, as expected 
alert(a.constructor.name == b.constructor.name); //true, as expected 

alert(c.constructor == d.constructor);    //true, as expected 
alert(c.constructor.name == d.constructor.name); //true, as expected 

alert(a.constructor == c.constructor);    //false, as expected 
alert(a.constructor.name == c.constructor.name); //true, as NOT expected 

तो क्या यह है? क्या हमें वास्तव में स्ट्रिंग के साथ a.constructor.name की तुलना के लिए आंतरिक कक्षा संरचना को जानने की आवश्यकता है? Nooooo, क्योंकि जावास्क्रिप्ट में आप सचमुच सब कुछ कर सकते हैं (आप बस पता है कि कैसे, की जरूरत नहीं क्यों), और मैं इस अंतिम समाधान पाया:

function Test(x){ 

    function Test(y){ 
     var variable = y; 

     this.getA = function(){ 
      return variable; 
     } 

     this.setA = function(x){ 
      variable = x; 
     } 
    } 
    return new Test(x); 
} 

function TestToo(x){ 

    function TestToo(y){ 
     var variable = y; 

     this.getA = function(){ 
      return variable; 
     } 

     this.setA = function(x){ 
      variable = x; 
     } 
    } 
    return new TestToo(x); 
} 

var a = Test("foo"); 
var b = Test("baz"); 

var c = TestToo("foo"); 
var d = TestToo("baz"); 

alert(a.constructor == b.constructor);    //true, as expected 
alert(a.constructor.name == b.constructor.name); //true, as expected 

alert(c.constructor == d.constructor);    //true, as expected 
alert(c.constructor.name == d.constructor.name); //true, as expected 

alert(a.constructor == c.constructor);    //false, as expected 
alert(a.constructor.name == c.constructor.name); //false, q.e.d.! 

मैं गंभीर हूँ, मुझे पता है क्यों यह नहीं है काम करता है। लेकिन यह निश्चित रूप से 100% काम करता है, 100% ऑब्जेक्ट encapsulation के साथ, और जावा कक्षाओं के लिए 1: 1 समानता। ;-)

+0

यह "गोटो": गोटो "टेस्ट" का उपयोग करने जैसा है, फिर "टेस्ट" नामक एक क्लास बनाएं और उस वर्ग को तुरंत चालू करें। साबित करता है कि जावास्क्रिप्ट फ़ंक्शंस प्रति वर्ग नहीं हैं, केवल तभी जब आप "नया" कहते हैं तो यह कक्षा बन जाता है! – Marcus

+0

समस्या: मुझे आईई में एक ही परिणाम नहीं मिलते हैं! परिणाम यह है: 'a.constructor == b.constructor// false' और 'a.constructor.name == b.constructor.name // true' IE में है। लेकिन फिर भी कार्य स्वयं सही तरीके से काम करते हैं।% D – Marcus