是否有可能在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已被更改!”:)

其他回答

如果你正在使用jQuery {UI}(每个人都应该使用:-)),你可以使用.change()和一个隐藏的<input/>元素。

在getter和setter的帮助下,您可以定义一个JavaScript类来做这样的事情。

首先,我们定义一个名为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;
  }
}

假设我们想监听钱的变化,让我们创建一个初始值为0的MonitoredVariable实例:

const money = new MonitoredVariable(0);

然后我们可以使用money来获取或设置它的值。

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

因为我们没有为它定义任何监听器,所以在钱之后没有什么特别的事情发生。Val变成了2。

现在让我们定义一些侦听器。我们有四个可用的侦听器:beforeSet、beforeChange、afterChange、afterSet。 当你使用金钱时,下面的事情会依次发生。val = newValue更改变量的值:

钱。beforeSet (newValue oldValue); 钱。beforeChange (newValue oldValue);(如果它的值没有改变,将被跳过) 钱。val = newValue; 钱。afterChange (newValue oldValue);(如果它的值没有改变,将被跳过) 钱。afterSet (newValue oldValue);

现在我们定义了afterChange监听器,它只会在金钱之后被触发。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。

一个相当简单和简单的解决方案是只使用函数调用来设置全局变量的值,而不要直接设置它的值。这样你就可以完全控制:

var globalVar;

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

没有办法强制执行,它只需要编程纪律……尽管你可以使用grep(或类似的东西)来检查你的代码没有直接设置globalVar的值。

或者你可以把它封装在一个对象和用户getter和setter方法中…只是一个想法。

我找到了最简单的方法,从这个答案开始:

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

这是一个古老而伟大的问题,已经超过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>