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


当前回答

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

/ /控制台 函数print(t) { var c = document.getElementById('console'); c.innerHTML = c.innerHTML + '<br />' + t; } / /演示 var myVar = 123; Object.defineProperty(this, 'varWatch', { get: function(){返回myVar;}, 集合:函数(v) { myVar = v; 打印(“价值变化!新值:' + v); } }); 打印(varWatch); varWatch = 456; 打印(varWatch); < pre id =“控制台”> < / >之前

其他的例子

// Console function print(t) { var c = document.getElementById('console'); c.innerHTML = c.innerHTML + '<br />' + t; } // Demo var varw = (function (context) { /** * Declare a new variable. * * @param {string} Variable name. * @param {any | undefined} varValue Default/Initial value. * You can use an object reference for example. */ 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 without initial value print(varWatch); varWatch = 456; print(varWatch); print('---'); varw('otherVarWatch', 123); // Declare with initial value print(otherVarWatch); otherVarWatch = 789; print(otherVarWatch); <pre id="console"> </pre>

其他回答

这个问题是关于变量的,而不是对象属性!因此,我的方法是利用窗口对象及其自定义getter /setter,然后像“正常”变量(不像对象属性)一样使用/更改变量。

最简单的方法是@José Antonio Postigo在他的回答中(我投票了那个答案)。我在这里想做的是将其简化为一个更简单的“creator”函数(这样即使不理解对象getter /setter的人也可以轻松使用它)。

一个活生生的例子在这里:https://codepen.io/dimvai/pen/LYzzbpz

这是你必须拥有的一般“creator”函数:

let createWatchedVariable = (variableName,initialValue,callbackFunction) => {
    // set default callback=console.log if missing
    callbackFunction ??= function(){console.log(variableName+" changed to " + window[variableName])};
    // the actual useful code:
    Object.defineProperty(window, variableName, {
      set: function(value) {window["_"+variableName] = value; callbackFunction()},
      get: function() {return window["_"+variableName]}
    });
    window[variableName]=initialValue??null;
};

然后,不要使用var或let来声明变量,而是使用下面的语句:

// 1st approach - default callback//    
createWatchedVariable ('myFirstVariable',12);  
// instead of: let myFirstVariable = 12;

或者,为了使用你的自定义回调(而不是默认的console.log)使用:

// 2nd approach - set a custom callback//
var myCallback = ()=>{/*your custom code...*/}
// now use callback function as the third optional argument
createWatchedVariable('mySecondVariable',0,myCallback);

就是这样!现在,你可以像改变一个“正常”变量一样改变它:

myFirstVariable = 15;      // logs to console
myFirstVariable++;         // logs to console
mySecondVariable = 1001;   // executes your custom code
mySecondVariable++;        // executes your custom code

你正在寻找的功能可以通过使用“defineProperty()”方法来实现——这只适用于现代浏览器:

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

我写了一个jQuery扩展,有一些类似的功能,如果你需要更多的跨浏览器支持:

https://github.com/jarederaj/jQueue

对象的队列回调的jQuery小扩展 变量、对象或键的存在。你可以分配任意数量的 对可能受影响的任意个数的数据点的回调 进程在后台运行。jQueue监听并等待 您指定的这些数据开始存在,然后发射 纠正回调函数的参数。

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

var globalVar;

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

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

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

这个问题最初发布于2009年,现有的大多数答案要么过时,无效,要么需要包含庞大的库:

对象。观看和反对。Observe都已弃用,不应该使用。 onPropertyChange是一个DOM元素事件处理程序,只在某些版本的IE中工作。 object . defineproperty允许您将对象属性设置为不可变的,这将允许您检测尝试的更改,但它也将阻止任何更改。 定义setter和getter是可行的,但是它需要大量的设置代码,并且当您需要删除或创建新属性时,它不能很好地工作。

截至2018年,您现在可以使用代理对象来监视(和拦截)对对象的更改。它是专门为OP试图做的事情而建造的。这里有一个基本的例子:

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对象唯一的缺点是:

Proxy对象在旧的浏览器(如IE11)中不可用,而且polyfill不能完全复制Proxy功能。 代理对象对于特殊对象(例如Date)并不总是表现得像预期的那样——代理对象最好与普通对象或数组配对。

如果你需要观察对嵌套对象所做的更改,那么你需要使用一个专门的库,如Observable Slim(我已经发布了)。它是这样工作的:

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}}]

 

@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提供了非常类似的反应行为