जावास्क्रिप्ट में परिवर्तनशील परिवर्तन के लिए सुनना


462

जेएस में एक घटना होना संभव है जो एक निश्चित चर के मूल्य में आग लगने पर बदल जाती है? JQuery को स्वीकार किया जाता है।


@BenjaminGruenbaum शायद आप MutableObserver (DOM के लिए) कहना चाहते हैं। ऑब्जेक्ट केवल जेएस ऑब्जेक्ट्स के लिए है जो मुझे याद है।
हेलबाई

2
@ हेलबाई यह सवाल चर के बारे में है - डोम नहीं।
बेंजामिन ग्रुएनबाउम

9
@BenjaminGruenbaum के अनुसार developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/… Object.observe अप्रचलित या पदावनत है। अनुशंसित प्रतिस्थापन (उसी पृष्ठ के अनुसार) प्रॉक्सी वस्तु है।
स्टैनियस

4
प्रश्न केवल के बारे में पूछ रहा है variable, फिर भी यहां सभी उत्तर संदर्भित हैं property। मुझे आश्चर्य है कि अगर हम local variableपरिवर्तनों के लिए सुन सकते हैं ।
थ्रिक नुगरोतोमो

1
क्या इसका कोई जवाब है? मेरा मतलब है, एक का चयन करने के लिए
ब्रायन मेलर

जवाबों:


100

हाँ, यह अब पूरी तरह से संभव है!

मुझे पता है कि यह एक पुराना धागा है लेकिन अब यह प्रभाव एक्सेसर्स (गेटर्स और सेटर्स) का उपयोग करके संभव है: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Working_wb_Objects#Defining_getters_and_setters_set

आप इस तरह से एक वस्तु को परिभाषित कर सकते हैं, जिसमें aInternalक्षेत्र का प्रतिनिधित्व करता है a:

x = {
  aInternal: 10,
  aListener: function(val) {},
  set a(val) {
    this.aInternal = val;
    this.aListener(val);
  },
  get a() {
    return this.aInternal;
  },
  registerListener: function(listener) {
    this.aListener = listener;
  }
}

तब आप निम्नलिखित का उपयोग करके एक श्रोता को पंजीकृत कर सकते हैं:

x.registerListener(function(val) {
  alert("Someone changed the value of x.a to " + val);
});

इसलिए जब भी कुछ भी मूल्य बदलता है x.a, तो श्रोता फ़ंक्शन को निकाल दिया जाएगा। निम्नलिखित लाइन चलाने से अलर्ट पॉपअप आएगा:

x.a = 42;

यहां एक उदाहरण देखें: https://jsfiddle.net/5o1wf1bn/1/

आप एकल श्रोता स्लॉट के बजाय श्रोताओं की एक सरणी भी बना सकते हैं, लेकिन मैं आपको सबसे सरल संभव उदाहरण देना चाहता था।


6
यह प्रति वस्तु कोड का एक टन है, क्या इसे और अधिक पुन: प्रयोज्य बनाने का एक तरीका है?
वेल विक्टस

आपका कोड कहां है? क्या आपने इससे एक नया प्रश्न शुरू किया?
अकीरा

जब किसी नई संपत्ति को किसी ऑब्जेक्ट में जोड़ा गया है, या किसी को हटा दिया गया है, तो पता लगाने के तरीके के बारे में क्या?
माइकल

यह एक पुराना उत्तर है, लेकिन मैं यह जोड़ना चाहता था कि यह सरणी मानों के लिए अच्छी तरह से काम करता है और जब तक आप इसे धकेलने के बजाय सरणी का मान सेट करते हैं।
TabsNotSpaces

1
आपको बस एक एकल के बजाय श्रोताओं की एक सरणी की आवश्यकता है और फिर केवल कॉल करने के बजाय this.aListener(val), आपको सभी श्रोता कार्यों के माध्यम से लूप करना होगा और प्रत्येक एक को कॉल करना होगा val। आमतौर पर, विधि के addListenerबजाय कहा जाता है registerListener
अकीरा

74

इस प्रश्न के अधिकांश उत्तर या तो पुराने, अप्रभावी हैं, या बड़े फूला हुआ पुस्तकालयों को शामिल करने की आवश्यकता है:

  • Object.watch और Object.observe दोनों को हटा दिया गया है और इसका उपयोग नहीं किया जाना चाहिए।
  • onPropertyChange एक DOM एलिमेंट इवेंट हैंडलर है जो केवल IE के कुछ संस्करणों में काम करता है।
  • Object.defineProperty आपको एक ऑब्जेक्ट प्रॉपर्टी को अपरिवर्तनीय बनाने की अनुमति देता है, जो आपको प्रयास किए गए परिवर्तनों का पता लगाने की अनुमति देगा, लेकिन यह किसी भी परिवर्तन को अवरुद्ध करेगा।
  • सेटर्स और गेटर्स को परिभाषित करना काम करता है, लेकिन इसके लिए बहुत सारे सेटअप कोड की आवश्यकता होती है और जब आप नई संपत्तियों को हटाने या बनाने की आवश्यकता होती है तो यह अच्छी तरह से काम नहीं करता है।

आज, आप किसी ऑब्जेक्ट में किए गए परिवर्तनों की निगरानी (और अवरोधन) के लिए प्रॉक्सी ऑब्जेक्ट का उपयोग कर सकते हैं । यह उद्देश्य ओपी क्या करने की कोशिश कर रहा है के लिए बनाया गया है। यहाँ एक मूल उदाहरण दिया गया है:

var targetObj = {};
var targetProxy = new Proxy(targetObj, {
  set: function (target, key, value) {
      console.log(`${key} set to ${value}`);
      target[key] = value;
      return true;
  }
});

targetProxy.hello_world = "test"; // console: 'hello_world set to test'

Proxyऑब्जेक्ट की एकमात्र कमियां हैं:

  1. Proxyवस्तु (जैसे IE11 के रूप में) पुराने ब्राउज़र में उपलब्ध नहीं है और polyfill पूरी तरह से दोहराने नहीं कर सकते हैं Proxyकार्यक्षमता।
  2. प्रॉक्सी ऑब्जेक्ट हमेशा विशेष वस्तुओं (जैसे, Date) के साथ अपेक्षा के अनुसार व्यवहार नहीं करते हैं - Proxyऑब्जेक्ट को सादे ऑब्जेक्ट या एरे के साथ सबसे अच्छा जोड़ा जाता है।

यदि आपको किसी नेस्टेड ऑब्जेक्ट में किए गए परिवर्तनों का अवलोकन करने की आवश्यकता है , तो आपको एक विशेष पुस्तकालय का उपयोग करने की आवश्यकता है जैसे ऑब्जर्वेबल स्लिम (जो मैंने प्रकाशित किया है) जो इस तरह से काम करता है:

var test = {testing:{}};
var p = ObservableSlim.create(test, true, function(changes) {
    console.log(JSON.stringify(changes));
});

p.testing.blah = 42; // console:  [{"type":"add","target":{"blah":42},"property":"blah","newValue":42,"currentPath":"testing.blah",jsonPointer:"/testing/blah","proxy":{"blah":42}}]

1
मैं एक और कमी भी जोड़ूंगा, आप वास्तव में लक्ष्य वस्तु पर बदलाव नहीं देखते हैं, लेकिन केवल छद्म वस्तु पर। कुछ मामलों में, आप बस यह जानना चाहते हैं कि लक्ष्य वस्तु (यानी target.hello_world = "test") पर एक संपत्ति कब बदल जाती है
क्रिस्टियानो

2
you don't actually watch changes on the target object but only on proxy object- यह बिल्कुल सटीक नहीं है। Proxyवस्तु संशोधित नहीं है - यह लक्ष्य की यह की अपनी प्रति नहीं है। you just want to know when a property change on the target object- आप कर सकते हैं कि एक के साथ Proxy, यह है कि परदे के पीछे प्राथमिक उपयोग मामलों में से एक है।
इलियट बी।

2
नहीं, क्योंकि आप सीधे लक्ष्य को संशोधित कर रहे हैं। यदि आप संशोधन का निरीक्षण करना चाहते हैं target, तो आपको इसे प्रॉक्सी के माध्यम से करना होगा। हालांकि proxy.hello_world = "test"इसका मतलब यह नहीं है कि आप प्रॉक्सी को संशोधित कर रहे हैं, प्रॉक्सी अपरिवर्तित रहता है, targetसंशोधित हो जाता है (यदि आपका सेट हैंडलर ऐसा करने के लिए कॉन्फ़िगर किया गया है)। ऐसा लगता है कि आपकी बात यह है कि आप सीधे निरीक्षण नहीं कर सकते target.hello_world = "test"। यह सच है। सादा चर असाइनमेंट किसी भी प्रकार के ईवेंट का उत्सर्जन नहीं करते हैं। इसलिए हमें इस प्रश्न के उत्तर में वर्णित उपकरणों जैसे उपकरणों का उपयोग करना होगा।
इलियट बी।

2
शुक्रिया इलियट बी It sounds like your point is that you cannot directly observe target.hello_world = "test". That is true.। बिल्कुल यही मेरी बात है। मेरे मामले में मेरे पास एक ऑब्जेक्ट कहीं और बनाया गया है और किसी अन्य कोड द्वारा अपडेट किया गया है ... एक प्रॉक्सी, इस मामले में, उपयोगी नहीं है क्योंकि लक्ष्य पर बदलाव किए जाएंगे।
क्रिस्टियानो

1
@Cristiano मुझे लगता है कि इलियट जो कहना चाह रहा है वह यह है कि आप वास्तविक वस्तु के बजाय प्रॉक्सी का उपयोग कर सकते हैं , जिसका अर्थ है कि आप प्रॉक्सी को चारों ओर से गुजर सकते हैं जैसे कि यह आपकी वस्तु थी और ऐप के अन्य हिस्सों को आपके प्रॉक्सी के साथ इंटरैक्ट करें। प्रॉक्सी पर परिवर्तन वास्तविक वस्तु पर परिलक्षित होगा।
Zoltán Matók

33

नहीं।

लेकिन, अगर यह वास्तव में महत्वपूर्ण है, तो आपके पास 2 विकल्प हैं (पहला परीक्षण किया गया है, दूसरा नहीं है):

सबसे पहले, सेटर और गेटर्स का उपयोग करें, जैसे:

var myobj = {a : 1};

function create_gets_sets(obj) { // make this a framework/global function
    var proxy = {}
    for ( var i in obj ) {
        if (obj.hasOwnProperty(i)) {
            var k = i;
            proxy["set_"+i] = function (val) { this[k] = val; };
            proxy["get_"+i] = function ()    { return this[k]; };
        }
    }
    for (var i in proxy) {
        if (proxy.hasOwnProperty(i)) {
            obj[i] = proxy[i];
        }
    }
}

create_gets_sets(myobj);

तो आप कुछ ऐसा कर सकते हैं:

function listen_to(obj, prop, handler) {
    var current_setter = obj["set_" + prop];
    var old_val = obj["get_" + prop]();
    obj["set_" + prop] = function(val) { current_setter.apply(obj, [old_val, val]); handler(val));
}

फिर श्रोता की तरह सेट करें:

listen_to(myobj, "a", function(oldval, newval) {
    alert("old : " + oldval + " new : " + newval);
}

दूसरा, मैं वास्तव में भूल गया था, मैं इसके बारे में सोचने के दौरान सबमिट कर दूंगा :)

संपादित करें: ओह, मुझे याद है :) आप मूल्य पर नजर रख सकते हैं:

ऊपर myobj को देखते हुए, इस पर 'a' के साथ:

function watch(obj, prop, handler) { // make this a framework/global function
    var currval = obj[prop];
    function callback() {
        if (obj[prop] != currval) {
            var temp = currval;
            currval = obj[prop];
            handler(temp, currval);
        }
    }
    return callback;
}

var myhandler = function (oldval, newval) {
    //do something
};

var intervalH = setInterval(watch(myobj, "a", myhandler), 100);

myobj.set_a(2);

8
"देखना" वास्तव में एक बदलाव का पता लगाना नहीं है। यह घटना आधारित नहीं है, और निश्चित रूप से बहुत जल्द पूरे ऐप को धीमा कर देगा। ये दृष्टिकोण IMHO कभी भी वास्तविक परियोजना का हिस्सा नहीं होना चाहिए।
मुहम्मद बिन युसरत

28

उपयोग करना Prototype: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty

// Console
function print(t) {
  var c = document.getElementById('console');
  c.innerHTML = c.innerHTML + '<br />' + t;
}

// Demo
var myVar = 123;

Object.defineProperty(this, 'varWatch', {
  get: function () { return myVar; },
  set: function (v) {
    myVar = v;
    print('Value changed! New value: ' + v);
  }
});

print(varWatch);
varWatch = 456;
print(varWatch);
<pre id="console">
</pre>

अन्य उदाहरण

// Console
function print(t) {
  var c = document.getElementById('console');
  c.innerHTML = c.innerHTML + '<br />' + t;
}

// Demo
var varw = (function (context) {
  return function (varName, varValue) {
    var value = varValue;
  
    Object.defineProperty(context, varName, {
      get: function () { return value; },
      set: function (v) {
        value = v;
        print('Value changed! New value: ' + value);
      }
    });
  };
})(window);

varw('varWatch'); // Declare
print(varWatch);
varWatch = 456;
print(varWatch);

print('---');

varw('otherVarWatch', 123); // Declare with initial value
print(otherVarWatch);
otherVarWatch = 789;
print(otherVarWatch);
<pre id="console">
</pre>


दूसरा उदाहरण थोड़ा भ्रामक है, इसके varwलिए 2 तर्क की आवश्यकता होती है लेकिन आपके उदाहरण का हिस्सा फ़ंक्शन को केवल मान पैरामीटर के साथ बुलाया जा रहा है।
हलावुल्ल्का मास २ 28'१ka को १२:५०

22

एक पुराना धागा लाने के लिए क्षमा करें, लेकिन यहाँ उन लोगों के लिए थोड़ा मैनुअल है जो (मेरे जैसे!) नहीं देखते कि एली ग्रे का उदाहरण कैसे है:

var test = new Object();
test.watch("elem", function(prop,oldval,newval){
    //Your code
    return newval;
});

आशा है कि यह किसी की मदद कर सकता है


9
घड़ी फिलहाल क्रोम या सफारी पर समर्थित नहीं है, केवल फ़ायरफ़ॉक्स
पॉल मैकक्लेन

5
प्रति मोज़िला डेवलपर नेटवर्क, यह अनुशंसित नहीं है। Object.prototyp.watch () केवल परीक्षण के लिए अभिप्रेत था और इसका उपयोग उत्पादन कोड में नहीं किया जाना चाहिए। developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
डेनिस बार्टलेट

4
@PaMMcClean यह जवाब एली ग्रे के जवाब में था जिसमें एक पॉलीफ़िल शामिल था। gist.github.com/eligrey/384583
शौक़ीन

2
मोज़िला द्वारा घड़ी को हटा दिया गया है। यह उत्तर भ्रामक हो सकता है।
अरनौद

7

जैसा कि ल्यूक शेफ़र के जवाब ( नोट : यह उनकी मूल पोस्ट को संदर्भित करता है; लेकिन यहाँ सम्पूर्ण बिंदु संपादन के बाद मान्य है ), मैं आपके मूल्य तक पहुँचने के लिए गेट / सेट के तरीकों की एक जोड़ी का भी सुझाव दूंगा

हालाँकि मैं कुछ संशोधनों का सुझाव दूंगा (और इसलिए मैं पोस्ट कर रहा हूं ...)।

उस कोड के साथ एक समस्या यह है कि aऑब्जेक्ट myobjका क्षेत्र सीधे पहुंच योग्य है, इसलिए श्रोताओं को ट्रिगर किए बिना इसे एक्सेस करना / इसके मूल्य को बदलना संभव है:

var myobj = { a : 5, get_a : function() { return this.a;}, set_a : function(val) { this.a = val; }}
/* add listeners ... */
myobj.a = 10; // no listeners called!

encapsulation

इसलिए, यह सुनिश्चित करने के लिए कि श्रोताओं को वास्तव में बुलाया जाता है, हमें उस प्रत्यक्ष क्षेत्र तक पहुंच को प्रतिबंधित करना होगा a। ऐसा कैसे करें? एक बंद का उपयोग करें !

var myobj = (function() { // Anonymous function to create scope.

    var a = 5;            // 'a' is local to this function
                          // and cannot be directly accessed from outside
                          // this anonymous function's scope

    return {
        get_a : function() { return a; },   // These functions are closures:
        set_a : function(val) { a = val; }  // they keep reference to
                                            // something ('a') that was on scope
                                            // where they were defined
    };
})();

अब आप ल्यूक के प्रस्ताव के अनुसार श्रोताओं को बनाने और जोड़ने के लिए उसी विधि का उपयोग कर सकते हैं, लेकिन आप निश्चिंत हो सकते हैं कि किसी ओर को पढ़ने या लिखने के लिए कोई संभव तरीका aनहीं है!

प्रोग्राम्ड फ़ील्ड्स को प्रोग्रामेटिक रूप से जोड़ना

ल्यूक के ट्रैक पर अभी भी, मैं एक सरल तरीके से कॉल करने के माध्यम से ऑब्जेक्ट्स में संबंधित क्षेत्र और संबंधित गेटर्स / सेटर्स को जोड़ने का एक सरल तरीका प्रस्तावित करता हूं।

ध्यान दें कि यह केवल मूल्य प्रकारों के साथ ठीक से काम करेगा । इसके लिए संदर्भ प्रकारों के साथ काम करने के लिए , किसी प्रकार की गहरी प्रतिलिपि को लागू करना होगा ( उदाहरण के लिए इसे देखें )।

function addProperty(obj, name, initial) {
    var field = initial;
    obj["get_" + name] = function() { return field; }
    obj["set_" + name] = function(val) { field = val; }
}

यह पहले की तरह ही काम करता है: हम एक फंक्शन पर एक स्थानीय वैरिएबल बनाते हैं, और फिर हम एक क्लोजर बनाते हैं।

इसका इस्तेमाल कैसे करें? सरल:

var myobj = {};
addProperty(myobj, "total", 0);
window.alert(myobj.get_total() == 0);
myobj.set_total(10);
window.alert(myobj.get_total() == 10);

2
एन्कैप्सुलेशन के लिए +1। यह मेरा पहला विचार था, लेकिन मैं अंततः create_gets_sets विधि को जोड़ने की क्षमता चाहता था, और चूंकि यह अंधाधुंध है, इसलिए मूल्यों को छिपाना शांत नहीं है :) हम इसे एक कदम आगे ले जा सकते हैं और मूल्यों को छिपाने के लिए कुछ चीजें लिख सकते हैं, लेकिन मुझे लगता है कि मैंने जो कोड पोस्ट किया है वह ज्यादातर लोगों के लिए पर्याप्त भ्रमित कर रहा है ... हो सकता है कि इसके लिए कॉल हो ...
ल्यूक शेफर

6

यदि आप jQuery {UI} का उपयोग कर रहे हैं (जो कि हर किसी को :-) का उपयोग करना चाहिए), तो आप एक छिपे हुए <input> तत्व के साथ .change () का उपयोग कर सकते हैं।


7
मैं काफी नहीं समझता। आप एक छिपे हुए <input/>तत्व को एक चर कैसे जोड़ सकते हैं ?
पीटर ली

4
मुझे लगता है कि चक सुझाव दे रहा है कि आप jquery और फिर एक .change () ईवेंट श्रोता का उपयोग करके इनपुट का मान सेट कर सकते हैं। यदि आप .val () के साथ इनपुट के मान को अपडेट करते हैं तो .change () ईवेंट कॉलबैक में आग लग जाएगी।
जेरेडराज २४'१४

2
<input type="hidden" value="" id="thisOne" />और jQuery के साथ $("#thisOne").change(function() { do stuff here });और $("#thisOne").val(myVariableWhichIsNew);और फिर .change()इच्छा आग।
कावेरीम

2
यह मेरी पुस्तकों में सबसे अच्छा समाधान है। सरल, आसान। अपने कोड में चर को बदलने के बजाय, उदाहरण के लिए var1 = 'new value';, आप इसके बजाय इस छिपे हुए इनपुट का मान सेट करेंगे, फिर चर को बदलने के लिए एक श्रोता जोड़ें। $("#val1").on('change', function(){ val1 = this.val(); ... do the stuff that you wanted to do when val1 changed... }); $("#val1").val('new value');
टॉम वॉकर

2
किसी के लिए भी, जो मेरे जैसी ही समस्या है, यदि परिवर्तन ईवेंट न करें ट्रिगर $ ("#One") की कोशिश करता है। Val (myVariableWhichIsNew) .trigger ('परिवर्तन')। ऐसा करने में मदद करता है
Alator

6

AngularJS(मुझे पता है कि यह नहीं है JQuery, लेकिन इससे मदद मिल सकती है। [शुद्ध जेएस केवल सिद्धांत में अच्छा है]):

$scope.$watch('data', function(newValue) { ..

जहां "डेटा" क्षेत्र में आपके चर का नाम है।

Doc के लिए एक लिंक है।


दुर्भाग्य से यह आपको चर को दायरे में बाँधने के लिए मजबूर करता है
बर्बाद कर देता है

जब $scope.$apply()इसे चलाया जाता है तो इसे निकाल दिया जाता है
iamawebgeek

5

बाद में एक दो साल में उन लोगों के लिए:

अधिकांश ब्राउज़रों ((IE6 +) के लिए एक समाधान उपलब्ध है जो onpropertychange घटना और नए विशेष डिफाइनप्रोपर्टी का उपयोग करता है। मामूली पकड़ यह है कि आपको अपने चर को एक डोम ऑब्जेक्ट बनाने की आवश्यकता होगी।

पूरा ब्योरा:

http://johndyer.name/native-browser-get-set-properties-in-javascript/


3

आप जिस कार्यशीलता की तलाश कर रहे हैं, उसे "डिफाइनप्रोपर्टी ()" विधि के उपयोग से प्राप्त किया जा सकता है - जो केवल आधुनिक ब्राउज़रों के लिए उपलब्ध है:

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty

मैंने एक jQuery एक्सटेंशन लिखा है जिसमें कुछ समान कार्यक्षमता है यदि आपको अधिक क्रॉस ब्राउज़र समर्थन की आवश्यकता है:

https://github.com/jarederaj/jQueue

एक छोटा jQuery एक्सटेंशन जो एक चर, ऑब्जेक्ट, या कुंजी के अस्तित्व के लिए कतारबद्ध कॉलबैक को संभालता है। आप पृष्ठभूमि में चल रही प्रक्रियाओं से प्रभावित होने वाले किसी भी डेटा बिंदु पर कॉलबैक की कोई भी संख्या असाइन कर सकते हैं। jQueue सुनता है और इन आंकड़ों की प्रतीक्षा करता है जिन्हें आप अस्तित्व में आने के लिए निर्दिष्ट करते हैं और फिर अपने तर्कों के साथ सही कॉलबैक से निकालते हैं।


2

सीधे तौर पर नहीं: आपको किसी प्रकार के "AddListener / removeListener" इंटरफ़ेस के साथ एक जोड़ी गेटटर / सेटर की आवश्यकता है ... या एक NPAPI प्लगइन (लेकिन यह पूरी तरह से एक और कहानी है)।


1
//ex:
/*
var x1 = {currentStatus:undefined};
your need is x1.currentStatus value is change trigger event ?
below the code is use try it.
*/
function statusChange(){
    console.log("x1.currentStatus_value_is_changed"+x1.eventCurrentStatus);
};

var x1 = {
    eventCurrentStatus:undefined,
    get currentStatus(){
        return this.eventCurrentStatus;
    },
    set currentStatus(val){
        this.eventCurrentStatus=val;
      //your function();
    }
};

या

/*  var x1 = {
eventCurrentStatus:undefined,
currentStatus : {
    get : function(){
        return Events.eventCurrentStatus
        },
    set : function(status){
        Events.eventCurrentStatus=status;

    },
}*/
console.log("eventCurrentStatus = "+ x1.eventCurrentStatus);
x1.currentStatus="create"
console.log("eventCurrentStatus = "+ x1.eventCurrentStatus);
x1.currentStatus="edit"
console.log("eventCurrentStatus = "+ x1.eventCurrentStatus);
console.log("currentStatus = "+ x1.currentStatus);

या

/* global variable ku*/
    var jsVarEvents={};
    Object.defineProperty(window, "globalvar1", {//no i18n
        get: function() { return window.jsVarEvents.globalvarTemp},
        set: function(value) { window.window.jsVarEvents.globalvarTemp = value; }
    });
    console.log(globalvar1);
    globalvar1=1;
    console.log(globalvar1);

1

एक बल्कि सरल और सरलीकृत समाधान सिर्फ वैश्विक चर के मूल्य को निर्धारित करने के लिए एक फ़ंक्शन कॉल का उपयोग करना है, और इसके मूल्य को सीधे सेट नहीं करना है। इस तरह आपके पास कुल नियंत्रण है:

var globalVar;

function setGlobalVar(value) {
    globalVar = value;
    console.log("Value of globalVar set to: " + globalVar);
    //Whatever else
}

इसे लागू करने का कोई तरीका नहीं है, इसके लिए बस प्रोग्रामिंग अनुशासन की आवश्यकता होती है ... हालांकि आप यह grepजांचने के लिए (या कुछ इसी तरह) का उपयोग कर सकते हैं कि कहीं भी आपका कोड सीधे मूल्य निर्धारित नहीं करता हैglobalVar

या आप इसे किसी ऑब्जेक्ट और यूजर गेट्टर और सेटर मेथड्स में इनकैप्सुलेट कर सकते हैं ... बस एक विचार।


एक चर के लिए जो एक वस्तु की संपत्ति नहीं है, जिसे कोई भी एक्सेस कर सकता है - जैसा कि varईएस 6 मॉड्यूल में घोषित चर के साथ होता है - यह एकमात्र समाधान है।
amn

1

कृपया लोगों को याद है कि प्रारंभिक प्रश्न VARIABLES के लिए था, OBJECTS के लिए नहीं;)

ऊपर दिए गए सभी उत्तरों के अलावा, मैंने forTheWatch.js नाम से एक छोटी सी लीब बनाई , जो कि जावास्क्रिप्ट में सामान्य वैश्विक चर में परिवर्तन के लिए पकड़ने और कॉलबैक के लिए उसी तरह का उपयोग करती है।

JQUERY चर के साथ संगत, OBJECTS का उपयोग करने की कोई आवश्यकता नहीं है, और यदि आवश्यक हो तो आप सीधे कई चर का ARRAY पास कर सकते हैं।

यदि यह मददगार हो सकता है ...: https://bitbucket.org/esabora/forthewatch
मूल रूप से आपको बस फ़ंक्शन को कॉल करना होगा:
watchIt("theVariableToWatch", "varChangedFunctionCallback");

और प्रासंगिक होने पर अग्रिम क्षमा करें।


1

इस उत्तर से शुरू होने वाला सबसे आसान तरीका :

// variable holding your data
const state = {
  count: null,
  update() {
    console.log(`this gets called and your value is ${this.pageNumber}`);
  },
  get pageNumber() {
    return this.count;
  },
  set pageNumber(pageNumber) {
    this.count = pageNumber;
    // here you call the code you need
    this.update(this.count);
  }
};

और तब:

state.pageNumber = 0;
// watch the console

state.pageNumber = 15;
// watch the console

1

मेरे मामले में, मैं यह पता लगाने की कोशिश कर रहा था कि क्या मेरी परियोजना में शामिल कोई भी पुस्तकालय मुझे फिर से परिभाषित कर रहा है window.player। इसलिए, मेरे कोड की शुरुआत में, मैंने अभी किया:

Object.defineProperty(window, 'player', {
  get: () => this._player,
  set: v => {
    console.log('window.player has been redefined!');
    this._player = v;
  }
});

0

यह सीधे संभव नहीं है।

हालाँकि, यह CustomEvent का उपयोग करके किया जा सकता है: https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent/CustomEvent

नीचे दी गई विधि इनपुट के रूप में चर नामों की एक सरणी को स्वीकार करती है और प्रत्येक चर के लिए घटना श्रोता को जोड़ती है और चर के मूल्य में किसी भी बदलाव के लिए घटना को ट्रिगर करती है।

विधि मूल्य में परिवर्तन का पता लगाने के लिए मतदान का उपयोग करती है। आप मिलीसेकंड में टाइमआउट के लिए मूल्य बढ़ा सकते हैं।

function watchVariable(varsToWatch) {
    let timeout = 1000;
    let localCopyForVars = {};
    let pollForChange = function () {
        for (let varToWatch of varsToWatch) {
            if (localCopyForVars[varToWatch] !== window[varToWatch]) {
                let event = new CustomEvent('onVar_' + varToWatch + 'Change', {
                    detail: {
                        name: varToWatch,
                        oldValue: localCopyForVars[varToWatch],
                        newValue: window[varToWatch]
                    }
                });
                document.dispatchEvent(event);
                localCopyForVars[varToWatch] = window[varToWatch];
            }
        }
        setTimeout(pollForChange, timeout);
    };
    let respondToNewValue = function (varData) {
        console.log("The value of the variable " + varData.name + " has been Changed from " + varData.oldValue + " to " + varData.newValue + "!!!"); 
    }
    for (let varToWatch of varsToWatch) {
        localCopyForVars[varToWatch] = window[varToWatch];
        document.addEventListener('onVar_' + varToWatch + 'Change', function (e) {
            respondToNewValue(e.detail);
        });
    }
    setTimeout(pollForChange, timeout);
}

विधि को कॉल करके:

watchVariables(['username', 'userid']);

यह वैरिएबल उपयोगकर्ता नाम और उपयोगकर्ता के परिवर्तन का पता लगाएगा।


0

गेटटर और सेटर की सहायता से , आप जावास्क्रिप्ट क्लास को परिभाषित कर सकते हैं जो ऐसा काम करता है।

सबसे पहले, हम अपनी कक्षा को परिभाषित करते हैं MonitoredVariable:

class MonitoredVariable {
  constructor(initialValue) {
    this._innerValue = initialValue;
    this.beforeSet = (newValue, oldValue) => {};
    this.beforeChange = (newValue, oldValue) => {};
    this.afterChange = (newValue, oldValue) => {};
    this.afterSet = (newValue, oldValue) => {};
  }

  set val(newValue) {
    const oldValue = this._innerValue;
    // newValue, oldValue may be the same
    this.beforeSet(newValue, oldValue);
    if (oldValue !== newValue) {
      this.beforeChange(newValue, oldValue);
      this._innerValue = newValue;
      this.afterChange(newValue, oldValue);
    }
    // newValue, oldValue may be the same
    this.afterSet(newValue, oldValue);
  }

  get val() {
    return this._innerValue;
  }
}

मान लें कि हम moneyपरिवर्तनों के बारे में सुनना चाहते हैं, तो आइए MonitoredVariableआरंभिक धन के साथ एक उदाहरण बनाएं 0:

const money = new MonitoredVariable(0);

तब हम इसके मूल्य का उपयोग कर सकते हैं या सेट कर सकते हैं money.val:

console.log(money.val); // Get its value
money.val = 2; // Set its value

चूंकि हमने इसके लिए किसी श्रोता को परिभाषित नहीं किया है, इसलिए money.val2 में बदलाव के बाद कुछ खास नहीं होता है ।

अब कुछ श्रोताओं को परिभाषित करते हैं। हम चार श्रोताओं उपलब्ध है: beforeSet, beforeChange, afterChange, afterSet। जब आप money.val = newValueवैरिएबल के मान को बदलने के लिए उपयोग करते हैं तो निम्नलिखित क्रमिक रूप से होगा :

  1. money.beforeSet (newValue, oldValue);
  2. money.beforeChange (newValue, oldValue); (इसका मूल्य नहीं बदला गया तो छोड़ दिया जाएगा)
  3. money.val = newValue;
  4. money.afterChange (newValue, oldValue); (इसका मूल्य नहीं बदला गया तो छोड़ दिया जाएगा)
  5. money.afterSet (newValue, oldValue);

अब हम afterChangeश्रोता को परिभाषित करते हैं जिसे money.valबदलने के बाद ही ट्रिगर किया जाता है (जबकि afterSetनए मूल्य पुराने के समान होने पर भी ट्रिगर किया जाएगा):

money.afterChange = (newValue, oldValue) => {
  console.log(`Money has been changed from ${oldValue} to ${newValue}`);
};

अब एक नया मान सेट करें 3और देखें कि क्या होता है:

money.val = 3;

आप कंसोल में निम्नलिखित देखेंगे:

Money has been changed from 2 to 3

पूर्ण कोड के लिए, https://gist.github.com/yusanshi/65745acd23c8587236c50e54f25731ab देखें


-2

यह एक पुराना धागा है, लेकिन मैं कोणीय का उपयोग करते हुए समाधान की तलाश करते हुए दूसरे उच्चतम उत्तर (कस्टम श्रोताओं) पर ठोकर खाई। जबकि समाधान काम करता है, इस का उपयोग कर @Outputऔर घटना emitters को हल करने के लिए कोणीय बेहतर तरीके से बनाया गया है । कस्टम श्रोता जवाब में उदाहरण से दूर जा रहे हैं:

ChildComponent.html

<button (click)="increment(1)">Increment</button>

ChildComponent.ts

import {EventEmitter, Output } from '@angular/core';

@Output() myEmitter: EventEmitter<number> = new EventEmitter<number>();

private myValue: number = 0;

public increment(n: number){
  this.myValue += n;

  // Send a change event to the emitter
  this.myEmitter.emit(this.myValue);
}

ParentComponent.html

<child-component (myEmitter)="monitorChanges($event)"></child-component>
<br/>
<label>{{n}}</label>

ParentComponent.ts

public n: number = 0;

public monitorChanges(n: number){
  this.n = n;
  console.log(n);
}

अब nहर बार चाइल्ड बटन पर क्लिक करने पर यह पैरेंट पर अपडेट हो जाएगा । स्टैकब्लिट्ज़ काम कर रहा है


-3
Utils = {
    eventRegister_globalVariable : function(variableName,handlers){
        eventRegister_JsonVariable(this,variableName,handlers);
    },
    eventRegister_jsonVariable : function(jsonObj,variableName,handlers){
        if(jsonObj.eventRegisteredVariable === undefined) {
            jsonObj.eventRegisteredVariable={};//this Object is used for trigger event in javascript variable value changes ku
        }
        Object.defineProperty(jsonObj, variableName , {
                    get: function() { 
                        return jsonObj.eventRegisteredVariable[variableName] },
                    set: function(value) {
                        jsonObj.eventRegisteredVariable[variableName] = value; handlers(jsonObj.eventRegisteredVariable[variableName]);}
                    });
            }
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.