是否有可能在JS中有一个事件,当某个变量的值发生变化时触发?JQuery被接受。


当前回答

对于那些几年后收听的人来说:

大多数浏览器(和IE6+)都有一个解决方案,它使用onpropertychange事件和更新的规范defineProperty。有一点需要注意的是,您需要将变量设置为dom对象。

详情:

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

其他回答

@akira和@mo-d-genesis的解决方案可以进一步简化,因为在这个例子中DOM操作不依赖于状态:

CodePen

const render = (val) => {
  document.getElementById("numberDiv").innerHTML = val;
};

state = {
  _value_internal: undefined,
  set value(val) {
    // 1. set state value
    this._value_internal = val;
    // 2. render user interface
    render(val);
  },
  get value() {
    return this._value_internal;
  },
};

const onClick = () => {
  state.value = state.value + 1; // state change leads to re-render!
};

// set default value
state.value = 0;

对应的html:

<div id="numberDiv"></div>

<button onclick="onClick()">
  Click to rerender
</button>

备注:

我重命名了变量和函数,以更好地反映它们的语义。 仅供参考:通过改变变量,Svelte提供了非常类似的反应行为

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

基于akira的回答,我补充说,你可以通过listerner操纵dom。

https://jsfiddle.net/2zcr0Lnh/2/

javascript:

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) {
document.getElementById('showNumber').innerHTML = val;
});


x.a = 50;

function onClick(){
x.a = x.a + 1;
}

html:

<div id="showNumber">
 
</div>


<button onclick="onClick()">
click me to rerender
</button>

当变量x.a发生变化时,registerListener方法将被触发。

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

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

在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。