是否有可能在JS中有一个事件,当某个变量的值发生变化时触发?JQuery被接受。
当前回答
这不是一个理想的答案,但它所做的是在JavaScript中每100毫秒设置一个间隔,并检查变量是否被改变,当它被改变时,它会做一些事情(OP想要的任何事情),然后清除间隔,所以它有点模拟OP的要求。
let myvar = "myvar";
const checkChange = setInterval(() => {
if (myvar !== "myvar") {
console.log("My precious var has been changed!");
clearInterval(checkChange);
}
}, 100);
现在,如果myvar被更改为其他东西,那么这个程序会说“我宝贵的var已被更改!”:)
其他回答
这是一个老线程,但我在使用Angular寻找解决方案时偶然发现了第二高的答案(自定义侦听器)。虽然这个解决方案是可行的,但angular有一个更好的内置方法来解决这个问题,使用@Output和事件发射器。在自定义监听器回答中的例子:
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);
}
现在每次单击子按钮时都会更新非父按钮。工作stackblitz
不是直接的:你需要一个“addListener/removeListener”接口的一对getter/setter…或者一个NPAPI插件(但这完全是另一个故事)。
我来这里是为了寻找node js的相同答案。就在这里
const events = require('events');
const eventEmitter = new events.EventEmitter();
// Createing state to watch and trigger on change
let x = 10 // x is being watched for changes in do while loops below
do {
eventEmitter.emit('back to normal');
}
while (x !== 10);
do {
eventEmitter.emit('something changed');
}
while (x === 10);
我正在做的是设置一些事件发射器时,值被改变,并使用do while循环来检测它。
这是一个古老而伟大的问题,已经超过12年了。此外,有很多方法来解决它。然而,大多数都是复杂的或使用旧的JS概念,我们在2022年,我们可以使用ES6来改进我们的代码。
我将实现我经常使用的两个主要解决方案。
简单的变量
如果我们有一个简单的变量,我们不关心重用,那么我们可以将变量声明为一个对象。我们定义了一个set和get方法以及一个listener属性来处理“change”事件。
const $countBtn = document.getElementById('counter') const $output = document.getElementById('output') const counter = { v: 0, listener: undefined, set value(v) { this.v = v if (this.listener) this.listener(v) }, get value() { return this.v }, count() { this.value++ }, registerListener(callback) { this.listener = callback }, } const countOnClick = () => { counter.count() } $countBtn.onclick = countOnClick counter.registerListener(v => { $output.textContent = v }) counter.value = 50 #output { display: block; font-size: 2em; margin-top: 0.67em; margin-bottom: 0.67em; margin-left: 0; margin-right: 0; font-weight: bold; } <button id="counter">Count</button> <div id="output"></div>
用于重用的高级类
如果我们有多个变量,并且需要监视它们,我们可以创建一个类,然后将其应用于我们的变量。我建议在change之前和change之后添加两个侦听器,这将使您在不同的过程中灵活地使用变量。
class ObservableObject { constructor(v) { this.v = v ?? 0 this.on = { beforeChange(newValue, oldValue) {}, afterChange(newValue, oldValue) {}, } } set value(newValue) { const oldValue = this.v // newValue, oldValue are the same if (oldValue === newValue) return this.on.beforeChange(newValue, oldValue) this.v = newValue this.on.afterChange(newValue, oldValue) } get value() { return this.v } } const $countABtn = document.getElementById('counter-a') const $countBBtn = document.getElementById('counter-b') const $outputA = document.getElementById('output-a') const $outputB = document.getElementById('output-b') const counterA = new ObservableObject() const counterB = new ObservableObject() const countOnClick = counter => { counter.value++ } const onChange = (v, output) => { output.textContent = v } $countABtn.onclick = () => { countOnClick(counterA) } $countBBtn.onclick = () => { countOnClick(counterB) } counterA.on.afterChange = v => { onChange(v, $outputA) } counterB.on.afterChange = v => { onChange(v, $outputB) } counterA.value = 50 counterB.value = 20 .wrapper { display: flex; flex-flow: row wrap; justify-content: center; align-items: center; width: 100vw } .item { width: 50% } .output { display: block; font-size: 2em; margin-top: 0.67em; margin-bottom: 0.67em; margin-left: 0; margin-right: 0; font-weight: bold; } <div class="wrapper"> <div class="item"> <button id="counter-a">Count A</button> <div id="output-a" class="output"></div> </div> <div class="item"> <button id="counter-b">Count B</button> <div id="output-b" class="output"></div> </div> </div>
No.
但是,如果这真的很重要,你有两个选择(第一个是测试,第二个不是):
首先,使用setter和getter,如下所示:
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);