Mendengarkan perubahan variabel dalam JavaScript

462

Apakah mungkin untuk memiliki acara di JS yang menyala ketika nilai variabel tertentu berubah? JQuery diterima.

rashcroft22
sumber
@BenjaminGruenbaum mungkin Anda ingin mengatakan MutableObserver (untuk DOM). Objek hanya untuk objek JS dari yang saya ingat.
HellBaby
2
@ HellBaby pertanyaan ini adalah tentang variabel - bukan DOM.
Benjamin Gruenbaum
9
@BenjaminGruenbaum menurut developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/… Object.observe sudah usang atau tidak digunakan lagi. Pengganti yang disarankan (per halaman yang sama) adalah objek Proxy.
stannius
4
Pertanyaannya hanya menanyakan variable, namun semua jawaban di sini merujuk property. Saya ingin tahu apakah kita dapat mendengarkan local variableperubahan.
Thariq Nugrohotomo
1
apakah ada jawaban untuk ini? Maksud saya, untuk memilih satu
Braian Mellor

Jawaban:

100

Ya, ini sekarang sangat mungkin!

Saya tahu ini adalah utas lama tetapi sekarang efek ini dimungkinkan menggunakan pengakses (getter dan setter): https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Working_with_Objects#Defining_getters_and_setters

Anda bisa mendefinisikan objek seperti ini, yang aInternalmewakili bidang 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;
  }
}

Kemudian Anda dapat mendaftarkan pendengar menggunakan yang berikut:

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

Jadi, setiap kali ada perubahan nilai x.a, fungsi pendengar akan diaktifkan. Menjalankan baris berikut akan memunculkan popup peringatan:

x.a = 42;

Lihat contoh di sini: https://jsfiddle.net/5o1wf1bn/1/

Anda juga dapat menggunakan array pendengar alih-alih slot pendengar tunggal, tapi saya ingin memberi Anda contoh paling sederhana.

Akira
sumber
6
Ini adalah satu ton kode per objek, apakah ada cara untuk membuatnya lebih dapat digunakan kembali?
Vael Victus
Di mana kode Anda? Apakah Anda memulai pertanyaan baru darinya?
Akira
Bagaimana dengan cara mendeteksi ketika properti baru telah ditambahkan ke objek, atau satu telah dihapus?
Michael
Ini adalah jawaban lama, tetapi saya ingin menambahkan bahwa ini berfungsi dengan baik untuk nilai-nilai array dan selama Anda menetapkan nilai array daripada mendorongnya.
TabsNotSpaces
1
Anda hanya perlu memiliki array pendengar bukan satu dan kemudian bukan hanya menelepon this.aListener(val), Anda harus mengulang semua fungsi pendengar dan memanggil masing-masing lewat val. Biasanya, metode ini disebut addListenerbukan registerListener.
Akira
75

Sebagian besar jawaban untuk pertanyaan ini sudah usang, tidak efektif, atau memerlukan dimasukkannya perpustakaan besar yang membengkak:

  • Object.watch dan Object.observe sudah usang dan tidak boleh digunakan.
  • onPropertyChange adalah pengendali event elemen DOM yang hanya berfungsi di beberapa versi IE.
  • Object.defineProperty memungkinkan Anda membuat properti objek tidak dapat diubah, yang memungkinkan Anda mendeteksi perubahan yang dicoba, tetapi juga akan memblokir semua perubahan.
  • Menentukan setter dan getter berfungsi, tetapi membutuhkan banyak kode pengaturan dan tidak berfungsi dengan baik ketika Anda perlu menghapus atau membuat properti baru.

Hari ini, Anda sekarang dapat menggunakan objek Proxy untuk memantau (dan mencegat) perubahan yang dilakukan pada suatu objek. Ini adalah tujuan yang dibangun untuk apa yang OP coba lakukan. Inilah contoh dasar:

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'

Satu-satunya kelemahan Proxyobjek adalah:

  1. The Proxyobjek tidak tersedia di browser lama (seperti IE11) dan polyfill tidak bisa sepenuhnya meniruProxy fungsi.
  2. Objek proksi tidak selalu berperilaku seperti yang diharapkan dengan objek khusus (misalnya, Date) - Proxyobjek paling baik dipasangkan dengan Objek atau Array.

Jika Anda perlu mengamati perubahan yang dilakukan pada objek bersarang , maka Anda perlu menggunakan perpustakaan khusus seperti Observable Slim (yang telah saya terbitkan) yang berfungsi seperti ini:

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}}]
Elliot B.
sumber
1
Saya akan menambahkan juga kelemahan lain, Anda tidak benar-benar melihat perubahan pada objek target tetapi hanya pada objek proxy. Dalam beberapa kasus, Anda hanya ingin tahu kapan properti berubah pada objek target (yaitu target.hello_world = "test")
Cristiano
2
you don't actually watch changes on the target object but only on proxy object- itu tidak cukup akurat. The Proxyobjek tidak dimodifikasi - itu tidak memiliki salinan itu sendiri dari target. you just want to know when a property change on the target object- Anda dapat mencapainya dengan Proxy, itu salah satu kasus penggunaan utama untuk proxy.
Elliot B.
2
Tidak, karena Anda memodifikasi target secara langsung. Jika Anda ingin mengamati modifikasi target, maka Anda harus melakukannya melalui proxy. Namun proxy.hello_world = "test"tidak berarti Anda memodifikasi proxy, proxy tetap tidak berubah, targetakan dimodifikasi (jika set handler Anda dikonfigurasi untuk melakukannya). Sepertinya poin Anda adalah bahwa Anda tidak dapat mengamati secara langsung target.hello_world = "test". Itu benar. Tugas variabel biasa tidak memancarkan jenis acara apa pun. Itu sebabnya kita harus menggunakan alat seperti yang dijelaskan dalam jawaban untuk pertanyaan ini.
Elliot B.
2
Terima kasih Elliot B. It sounds like your point is that you cannot directly observe target.hello_world = "test". That is true.itu maksud saya. Dalam kasus saya, saya memiliki objek yang dibuat di tempat lain dan telah diperbarui oleh beberapa kode lain ... proxy, dalam hal ini, tidak berguna karena perubahan akan dilakukan pada target.
Cristiano
1
@Cristiano Saya kira apa yang Elliot coba katakan adalah bahwa Anda dapat menggunakan proxy daripada objek yang sebenarnya, yang berarti Anda dapat melewati proxy seperti jika itu adalah objek Anda dan membuat bagian lain aplikasi berinteraksi dengan proxy Anda. Perubahan pada proxy akan tercermin pada objek yang sebenarnya.
Zoltán Matók
33

Tidak.

Tapi, jika itu benar-benar penting, Anda memiliki 2 opsi (pertama diuji, kedua tidak):

Pertama, gunakan setter dan getter, seperti:

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);

maka Anda dapat melakukan sesuatu seperti:

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));
}

kemudian atur pendengar seperti:

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

Kedua, saya benar-benar lupa, saya akan serahkan sementara saya memikirkannya :)

EDIT: Oh, saya ingat :) Anda bisa memberi nilai pada jam tangan:

Diberikan myobj di atas, dengan 'a' di atasnya:

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);
Luke Schafer
sumber
8
"menonton" sebenarnya tidak mendeteksi perubahan. Ini bukan berbasis acara, dan tentu saja akan memperlambat seluruh aplikasi segera. Pendekatan-pendekatan ini IMHO tidak boleh menjadi bagian dari proyek nyata.
Muhammad bin Yusrat
28

Menggunakan 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>

Contoh lainnya

// 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>

Eduardo Cuomo
sumber
Contoh kedua agak menyesatkan, varwmembutuhkan 2 argumen tetapi bagian dari contoh Anda menunjukkan fungsi dipanggil hanya dengan parameter nilai.
Hlawuleka MAS
22

Maaf untuk membuka utas lama, tetapi di sini ada manual kecil bagi mereka yang (seperti saya!) Tidak melihat bagaimana contoh kerja Eli Grey:

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

Semoga ini bisa membantu seseorang

javascript adalah masa depan
sumber
9
Watch tidak didukung di Chrome atau Safari saat ini, hanya Firefox
Paul McClean
5
Per jaringan pengembang mozilla, ini tidak dianjurkan. Object.prototype.watch () dimaksudkan hanya untuk pengujian dan tidak boleh digunakan dalam kode produksi. developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
Dennis Bartlett
4
@PaulMcClean jawaban ini ada di Respon untuk jawaban Eli Grey yang berisi Polyfill. gist.github.com/eligrey/384583
Hobbyist
2
jam tangan telah ditinggalkan oleh Mozilla. Jawaban ini bisa menyesatkan.
Arnaud
7

Sebagai jawaban Luke Schafer ( catatan : ini merujuk pada posting aslinya; tetapi seluruh poin di sini tetap valid setelah diedit ), saya juga menyarankan sepasang metode Get / Set untuk mengakses nilai Anda.

Namun saya akan menyarankan beberapa modifikasi (dan itulah sebabnya saya memposting ...).

Masalah dengan kode itu adalah bahwa bidang aobjek myobjdapat diakses secara langsung, sehingga dimungkinkan untuk mengaksesnya / mengubah nilainya tanpa memicu pendengar:

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!

Enkapsulasi

Jadi, untuk menjamin bahwa pendengar benar-benar dipanggil, kita harus melarang akses langsung ke lapangan a. Bagaimana cara melakukannya? Gunakan penutupan !

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
    };
})();

Sekarang Anda dapat menggunakan metode yang sama untuk membuat dan menambahkan pendengar seperti yang diusulkan Luke, tetapi Anda dapat yakin bahwa tidak ada cara yang mungkin untuk membaca atau menulis agar atidak diperhatikan!

Menambahkan bidang enkapsulasi secara pemrograman

Masih di jalur Luke, sekarang saya usulkan cara sederhana untuk menambahkan bidang enkapsulasi dan masing-masing getter / setter ke objek dengan cara pemanggilan fungsi sederhana.

Perhatikan bahwa ini hanya akan berfungsi dengan baik dengan tipe nilai . Agar ini bekerja dengan tipe referensi , beberapa jenis salinan yang dalam harus diimplementasikan (lihat yang ini , misalnya).

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

Ini berfungsi sama seperti sebelumnya: kita membuat variabel lokal pada suatu fungsi, dan kemudian kita membuat penutupan.

Bagaimana cara menggunakannya? Sederhana:

var myobj = {};
addProperty(myobj, "total", 0);
window.alert(myobj.get_total() == 0);
myobj.set_total(10);
window.alert(myobj.get_total() == 10);
Bruno Reis
sumber
2
+1 untuk enkapsulasi. Itu adalah pemikiran pertama saya, tetapi saya ingin kemampuan untuk menambahkan metode create_gets_sets pada akhirnya, dan karena tidak pandang bulu, menyembunyikan nilai tidak keren :) kita dapat mengambil langkah lebih jauh dan menulis beberapa hal untuk menyembunyikan nilai, tetapi saya pikir kode saya sudah diposting cukup membingungkan bagi kebanyakan orang ... mungkin jika ada panggilan untuk itu ...
Luke Schafer
6

Jika Anda menggunakan jQuery {UI} (yang harus digunakan semua orang :-)), Anda dapat menggunakan .change () dengan elemen <input /> tersembunyi.

Chuck Han
sumber
7
Saya tidak begitu mengerti. Bagaimana Anda bisa melampirkan variabel ke <input/>elemen tersembunyi ?
Peter Lee
4
Saya pikir Chuck menyarankan agar Anda dapat mengatur nilai input menggunakan jquery dan kemudian dan pendengar acara .change (). Jika Anda memperbarui nilai input dengan .val () maka callback .change () akan aktif.
jarederaj
2
<input type="hidden" value="" id="thisOne" />dan dengan jQuery $("#thisOne").change(function() { do stuff here });dan $("#thisOne").val(myVariableWhichIsNew);dan kemudian .change()akan api.
khaverim
2
Ini adalah solusi terbaik dalam buku saya. Sederhana, mudah. Alih-alih mengubah variabel dalam kode Anda, misalnya var1 = 'new value';, Anda malah akan menetapkan nilai input tersembunyi ini, lalu menambahkan pendengar untuk mengubah variabel. $("#val1").on('change', function(){ val1 = this.val(); ... do the stuff that you wanted to do when val1 changed... }); $("#val1").val('new value');
Tom Walker
2
Bagi siapa saja yang memiliki masalah yang sama seperti saya, jika perubahan memicu event doesnt mencoba $ ( "# thisone") val (myVariableWhichIsNew) .trigger ( 'perubahan') .hope ini membantu.
Alator
6

AngularJS(Saya tahu ini bukan JQuery, tapi itu mungkin bisa membantu. [JS Murni hanya baik secara teori]):

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

di mana "data" adalah nama variabel Anda dalam cakupan.

Ada tautan ke doc.

ses
sumber
Sayangnya itu memaksa Anda untuk mengikat variabel ke lingkup
ruX
itu dipecat hanya ketika $scope.$apply()dijalankan
iamawebgeek
3

Fungsionalitas yang Anda cari dapat dicapai melalui penggunaan metode "defineProperty ()" - yang hanya tersedia untuk browser modern:

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

Saya telah menulis ekstensi jQuery yang memiliki beberapa fungsi serupa jika Anda memerlukan lebih banyak dukungan lintas browser:

https://github.com/jarederaj/jQueue

Ekstensi jQuery kecil yang menangani antrean panggilan balik ke keberadaan variabel, objek, atau kunci. Anda dapat menetapkan sejumlah panggilan balik ke sejumlah titik data yang mungkin dipengaruhi oleh proses yang berjalan di latar belakang. jQueue mendengarkan dan menunggu data yang Anda tentukan muncul dan kemudian memecat callback yang benar dengan argumennya.

jarederaj
sumber
2

Tidak secara langsung: Anda memerlukan sepasang pengambil / penyetel dengan antarmuka "addListener / removeListener" semacam ... atau sebuah plugin NPAPI (tapi itu cerita lain sama sekali).

jldupont
sumber
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();
    }
};

atau

/*  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);

atau

/* 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);
Avatar
sumber
1

Solusi yang agak sederhana dan sederhana adalah dengan hanya menggunakan pemanggilan fungsi untuk mengatur nilai variabel global, dan tidak pernah menetapkan nilainya secara langsung. Dengan cara ini Anda memiliki kontrol total:

var globalVar;

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

Tidak ada cara untuk menegakkan ini, itu hanya membutuhkan disiplin pemrograman ... meskipun Anda dapat menggunakan grep(atau sesuatu yang serupa) untuk memeriksa bahwa tidak ada kode yang langsung mengatur nilaiglobalVar .

Atau Anda bisa merangkumnya dalam objek dan metode pengambil dan penyetel pengguna ... hanya pemikiran.

markvgti
sumber
Untuk variabel yang bukan properti objek yang dapat diakses - seperti halnya variabel yang dideklarasikan vardalam modul ES6 - ini adalah satu - satunya solusi.
amn
1

Tolong ingat pertanyaan awal adalah untuk VARIABEL, bukan untuk BENDA;)

selain semua jawaban di atas, saya membuat lib kecil bernama forTheWatch.js , yang menggunakan cara yang sama untuk menangkap dan balik untuk perubahan dalam variabel global normal dalam javascript.

Kompatibel dengan variabel JQUERY, tidak perlu menggunakan OBYEK, dan Anda dapat melewati secara langsung ARRAY dari beberapa variabel jika diperlukan.

Jika ini bisa membantu ...: https://bitbucket.org/esabora/forthewatch
Pada dasarnya Anda hanya perlu memanggil fungsi:
watchIt("theVariableToWatch", "varChangedFunctionCallback");

Dan maaf sebelumnya jika tidak relevan.

Soufiane Benrazzouk
sumber
1

Cara termudah yang saya temukan, mulai dari jawaban ini :

// 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);
  }
};

Lalu:

state.pageNumber = 0;
// watch the console

state.pageNumber = 15;
// watch the console
Giorgio Tempesta
sumber
1

Dalam kasus saya, saya mencoba mencari tahu apakah ada perpustakaan yang saya masukkan dalam proyek saya yang mendefinisikan ulang perpustakaan saya window.player. Jadi, pada awal kode saya, saya baru saja melakukannya:

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

Itu tidak mungkin secara langsung.

Namun, ini dapat dilakukan dengan menggunakan CustomEvent: https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent/CustomEvent

Metode di bawah ini menerima array nama variabel sebagai input dan menambahkan pendengar acara untuk setiap variabel dan memicu acara untuk setiap perubahan pada nilai variabel.

Metode menggunakan polling untuk mendeteksi perubahan nilai. Anda dapat meningkatkan nilai waktu habis dalam milidetik.

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);
}

Dengan memanggil Metode:

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

Ini akan mendeteksi perubahan pada variabel username dan userid.

Ketan Yekale
sumber
0

Dengan bantuan pengambil dan penyetel , Anda dapat menentukan kelas JavaScript yang melakukan hal seperti itu.

Pertama, kita mendefinisikan kelas kita yang disebut 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;
  }
}

Anggap kita ingin mendengarkan moneyperubahan, mari kita membuat contoh MonitoredVariabledengan uang awal 0:

const money = new MonitoredVariable(0);

Lalu kita bisa mendapatkan atau mengatur nilainya menggunakan money.val:

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

Karena kami belum menetapkan pendengar untuk itu, tidak ada yang istimewa terjadi setelah money.valperubahan ke 2.

Sekarang mari kita mendefinisikan beberapa pendengar. Kami memiliki empat pendengar yang tersedia: beforeSet, beforeChange, afterChange, afterSet. Berikut ini akan terjadi secara berurutan ketika Anda digunakan money.val = newValueuntuk mengubah nilai variabel:

  1. money.beforeSet (newValue, oldValue);
  2. money.beforeChange (newValue, oldValue); (Akan dilewati jika nilainya tidak berubah)
  3. money.val = newValue;
  4. money.afterChange (newValue, oldValue); (Akan dilewati jika nilainya tidak berubah)
  5. money.afterSet (newValue, oldValue);

Sekarang kita mendefinisikan afterChangependengar yang dipicu hanya setelah money.valtelah berubah (sementara afterSetakan dipicu bahkan jika nilai baru sama dengan yang lama):

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

Sekarang tetapkan nilai baru 3dan lihat apa yang terjadi:

money.val = 3;

Anda akan melihat yang berikut di konsol:

Money has been changed from 2 to 3

Untuk kode lengkap, lihat https://gist.github.com/yusanshi/65745acd23c8587236c50e54f25731ab .

yusanshi
sumber
-2

Ini adalah utas lama tapi saya menemukan jawaban tertinggi kedua (pendengar khusus) sambil mencari solusi menggunakan Angular. Sementara solusinya bekerja, angular memiliki cara yang lebih baik untuk menyelesaikan penggunaan @Outputdan pemancar acara ini. Keluar dari contoh dalam jawaban pendengar khusus:

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);
}

Ini sekarang akan diperbarui npada orang tua setiap kali tombol anak diklik. Bekerja stackblitz

TabsNotSpaces
sumber
-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]);}
                    });
            }
Avatar
sumber