2013-02-10 24 views
8

मैं हाल ही में कोणीय और उल्का जैसे जावास्क्रिप्ट ढांचे में देख रहा हूं, और मैं सोच रहा था कि जब कोई वस्तु संपत्ति बदल गई है तो वे कैसे जानते हैं ताकि वे डोम अपडेट कर सकें।वस्तुओं को देखने योग्य बनाने योग्य

मैं थोड़ा आश्चर्यचकित था कि कोणीय ने कुछ प्रकार के गेटर/सेटर को कॉल करने की आवश्यकता के बजाय सादे पुराने जेएस ऑब्जेक्ट्स का उपयोग किया ताकि वह आवश्यक अपडेट कर सके और कर सके। मेरी समझ यह है कि वे नियमित रूप से परिवर्तनों के लिए वस्तुओं को नियमित रूप से मतदान करते हैं।

लेकिन JS 1.8.5 में गेटर्स और सेटर्स के आगमन के साथ, हम उससे बेहतर कर सकते हैं, है ना?

(संपादित करें:: अद्यतन कोड निर्भर-संपत्ति जोड़ने के लिए/विधि समर्थन)

function dependentProperty(callback, deps) { 
    callback.__dependencies__ = deps; 
    return callback; 
} 

var person = { 
    firstName: 'Ryan', 
    lastName: 'Gosling', 
    fullName: dependentProperty(function() { 
     return person.firstName + ' ' + person.lastName; 
    }, ['firstName','lastName']) 
}; 

function observable(obj) { 
    if (!obj.__properties__) Object.defineProperty(obj, '__properties__', { 
     __proto__: null, 
     configurable: false, 
     enumerable: false, 
     value: {}, 
     writable: false 
    }); 
    for (var prop in obj) { 
     if (obj.hasOwnProperty(prop)) { 
      if(!obj.__properties__[prop]) obj.__properties__[prop] = { 
       value: null, 
       dependents: {}, 
       listeners: [] 
      }; 
      if(obj[prop].__dependencies__) { 
       for(var i=0; i<obj[prop].__dependencies__.length; ++i) { 
        obj.__properties__[obj[prop].__dependencies__[i]].dependents[prop] = true; 
       } 
       delete obj[prop].__dependencies__; 
      } 
      obj.__properties__[prop].value = obj[prop]; 
      delete obj[prop]; 
      (function (prop) { 
       Object.defineProperty(obj, prop, { 
        get: function() { 
         return obj.__properties__[prop].value; 
        }, 
        set: function (newValue) { 
         var oldValue = obj.__properties__[prop].value; 
         if(oldValue !== newValue) { 
          var oldDepValues = {}; 
          for(var dep in obj.__properties__[prop].dependents) { 
           if(obj.__properties__[prop].dependents.hasOwnProperty(dep)) { 
            oldDepValues[dep] = obj.__properties__[dep].value(); 
           } 
          } 
          obj.__properties__[prop].value = newValue; 
          for(var i=0; i<obj.__properties__[prop].listeners.length; ++i) { 
           obj.__properties__[prop].listeners[i](oldValue, newValue); 
          } 
          for(dep in obj.__properties__[prop].dependents) { 
           if(obj.__properties__[prop].dependents.hasOwnProperty(dep)) { 
            var newDepValue = obj.__properties__[dep].value(); 
            for(i=0; i<obj.__properties__[dep].listeners.length; ++i) { 
             obj.__properties__[dep].listeners[i](oldDepValues[dep], newDepValue); 
            } 
           } 
          } 
         } 
        } 
       }); 
      })(prop); 
     } 
    } 
    return obj; 
} 

function listen(obj, prop, callback) { 
    if(!obj.__properties__) throw 'object is not observable'; 
    obj.__properties__[prop].listeners.push(callback); 
} 

observable(person); 

listen(person, 'fullName', function(oldValue, newValue) { 
    console.log('Name changed from "'+oldValue+'" to "'+newValue+'"'); 
}); 

person.lastName = 'Reynolds'; 

कौन सा लॉग:

एक छोटे-का-प्रमाण अवधारणा के रूप में, मैं एक साथ इस स्क्रिप्ट को

नाम "रयान गोसलिंग" से "रायन रेनॉल्ड्स"

से बदल

एकमात्र समस्या जो मैं देखता हूं वह परिभाषा विधियों जैसे कि fullName() व्यक्ति वस्तु पर है जो अन्य दो गुणों पर निर्भर करेगी। डेवलपर्स को निर्भरता निर्दिष्ट करने की अनुमति देने के लिए ऑब्जेक्ट पर थोड़ा अतिरिक्त मार्कअप की आवश्यकता होती है।

इसके अलावा, क्या इस दृष्टिकोण के लिए कोई डाउनसाइड्स हैं? जे एस 1.8.5 में getters और setters के

JsFiddle

+0

नकारात्मकता यह होगी कि आपको यह लिखना होगा। आप ऐसा क्यों करेंगे जब पुस्तकालय हैं जो आपके लिए करते हैं? –

+1

@AshBurlaczenko: इसे एक सीखने का अभ्यास कहते हैं। – mpen

+0

एक तरफ नोट पर, [नॉकआउटजेएस] (http://knockoutjs.com/) समान रूप से काम करता है, केवल यह जेएस 185 फीचर्स AFAIK का उपयोग नहीं करता है। – Jeroen

उत्तर

1

आगमन - वहाँ इस दृष्टिकोण के लिए किसी भी कमियां हैं?

  • आपने देखा लोगों से अलग किसी भी संपत्ति परिवर्तन पर कब्जा नहीं है। निश्चित रूप से, यह मॉडलिंग इकाई वस्तुओं के लिए पर्याप्त है, और किसी और चीज के लिए हम प्रॉक्सी का उपयोग कर सकते हैं।
  • यह उन ब्राउज़रों तक सीमित है जो गेटर्स/सेटर्स का समर्थन करते हैं, और शायद प्रॉक्सी भी। लेकिन हे, पुराने ब्राउज़र के बारे में कौन परवाह करता है? :-) और प्रतिबंधित वातावरण (Node.js) में यह बिल्कुल नहीं है।
  • एक्सेसर गुण (गेटटर और सेटर के साथ) वास्तविक get/set विधियों की तुलना में बहुत धीमे हैं। बेशक, मुझे उम्मीद नहीं है कि उन्हें महत्वपूर्ण वर्गों में इस्तेमाल किया जाए, और वे कोड को ज्यादा प्रशंसक बना सकते हैं। फिर भी आपको इसे अपने दिमाग के पीछे रखना होगा। इसके अलावा, फैंसी-दिखने वाला कोड गलत धारणाओं का कारण बन सकता है - आम तौर पर आप संपत्ति असाइनमेंट/एक लघु (O(1)) ऑपरेशन तक पहुंचने की अपेक्षा करेंगे, जबकि गेटर्स/सेटर्स के साथ बहुत कुछ हो रहा है। आपको इसे भूलने की परवाह करने की आवश्यकता नहीं होगी, और वास्तविक तरीकों का उपयोग करने में मदद मिल सकती है।

तो अगर हम जानते हैं कि हम क्या कर रहे हैं, हाँ, हम बेहतर कर सकते हैं।

फिर भी, एक विशाल बिंदु है जिसे हमें याद रखने की आवश्यकता है: सिंक्रोनिटी/एसिंक्रोनिटी (this excellent answer पर भी एक नज़र डालें)। कोणीय की गंदे जांच आपको से पहले गुणों का एक गुच्छा बदलने की अनुमति देती है घटना अगले ईवेंट लूप बारी में आग लगती है। यह अर्थात् अमान्य राज्यों से बचने (प्रचार) करने में मदद करता है।

फिर भी मैं एक मौका के रूप में सिंक्रोनस गेटर्स/सेटर्स को भी देखता हूं। वे हमें घोषित करने की अनुमति देते हैं और गुणों के बीच मान्यताओं को परिभाषित करते हैं। यह स्वचालित रूप से मॉडल की शुद्धता सुनिश्चित करेगा, जबकि हमें केवल एक ही समय में एक संपत्ति को बदलना होगा (firstName और fullName को बदलने के बजाय, हर समय firstName पर्याप्त है)। फिर भी, निर्भरता के दौरान हल करना जो सच नहीं हो सकता है इसलिए हमें इसकी परवाह करने की आवश्यकता है।

तो, श्रोताओं जो निर्भरता प्रबंधन से संबंधित नहीं हैं, को एसिंक्रोनस से निकाल दिया जाना चाहिए। बस setImmediate उनके लूप।

+0

(1) "कोणीय की गंदे जांच से आप एक बार में गुणों का एक गुच्छा बदल सकते हैं घटना अगले कार्यक्रम लूप बारी में आग लगती है "- मैंने इसे पहले से ही दो बार संबोधित किया। ईवेंट हैंडलर को तुरंत आग लगाने की कोई ज़रूरत नहीं है, हम सिर्फ संपत्ति को गंदे के रूप में ध्वजांकित कर सकते हैं और अंत में सभी हैंडलरों को आग लगा सकते हैं, जैसा कि कोणीय करता है लेकिन हर संपत्ति की जांच करने की आवश्यकता के बिना। (2) अधिकांश भाग के लिए हमें पता होना चाहिए कि किन संपत्तियों को देखने की आवश्यकता है क्योंकि हमें उन चरों पर घड़ियों को सेट करने के लिए टेम्पलेट को पार्स करना होगा। एक जोड़े हो सकता है जिसके कारण हम चूक गए ... – mpen

+0

... गैर मानक उपयोग, लेकिन यह फिर से कोणीय के समान ही कम है। आपको उन मामलों में मैन्युअल रूप से घड़ी/श्रोता जोड़ना होगा। (3) सेटर्स 'ओ (1) 'क्यों नहीं होंगे? मान लें कि हम ईवेंट के अंत तक हैंडलर के निष्पादन में देरी करते हैं, हमें केवल संपत्ति को "गंदे" गुणों के सेट में धक्का देना पड़ता है और फिर इसे बाद में संभालता है, जो केवल एक छोटा निरंतर समय ओवरहेड जोड़ता है, जो कम से कम होना चाहिए प्रत्येक घटना के बाद * सब कुछ * की जांच की बड़ी लागत। – mpen

+1

ऑन (2): मैं कोणीय से परिचित नहीं हूं, और इसकी सटीक कार्यप्रणाली को नहीं जानता - मैंने सोचा कि मतदान के साथ आप अन्य गुणों का भी पता लगा सकते हैं। मेरा बिंदु ढांचे को कम करने के लिए समर्पित नहीं था, लेकिन अधिक सामान्य - यह बिल्कुल हर जगह लागू नहीं है। (3) हां, यदि आप सेटर्स के निष्पादन में देरी करते हैं और केवल गंदे झंडे सेट करते हैं, तो आप * इसे लगातार ओवरहेड बना सकते हैं। हालांकि मेरा मुद्दा जोखिम के बारे में था कि प्रोग्रामर जो सरल असाइनमेंट का उपयोग करता है (ओ (1) की अपेक्षा करता है) बिल्कुल नहीं जानता कि दृश्यों के पीछे क्या होता है (या यहां तक ​​कि इसके बारे में शायद नहीं पता)। – Bergi

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