是否有可能在JS中有一个事件,当某个变量的值发生变化时触发?JQuery被接受。
当前回答
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);
其他回答
我搜索了JavaScript双向数据绑定库,发现了这个库。
我没有成功地使它在DOM到变量的方向上工作,但在变量到DOM的方向上它是工作的,这就是我们在这里需要的。
我稍微重写了一下,因为原始代码(对我来说)很难阅读。它使用 object。defineproperty,这是Eliot b给出的第二多赞的答案,至少有部分错误。
<!DOCTYPE html>
<html>
<head>
<title>TODO supply a title</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script>
const dataBind = (function () {
const getElementValue = function (selector) {
let element = document.querySelectorAll(selector)[0];
return 'value' in element ? element.value : element.innerHTML;
};
const setElementValue = function (selector, newValue) {
let elementArray = document.querySelectorAll(selector);
for (let i = 0; i < elementArray.length; i++) {
let element = elementArray[i];
if ('value' in element) {
element.value = newValue;
if (element.tagName.toLowerCase() === 'select'){
let options = element.querySelectorAll('option');
for (let option in options){
if (option.value === newValue){
option.selected = true;
break;
}
}
}
} else {
element.innerHTML = newValue;
}
}
};
const bindModelToView = function (selector, object, property, enumerable) {
Object.defineProperty(object, property, {
get: function () {
return getElementValue(selector);
},
set: function (newValue) {
setElementValue(selector, newValue);
},
configurable: true,
enumerable: (enumerable)
});
};
return {
bindModelToView
};
})();
</script>
</head>
<body>
<div style="padding: 20%;">
<input type="text" id="text" style="width: 40px;"/>
</div>
<script>
let x = {a: 1, b: 2};
dataBind.bindModelToView('#text', x, 'a'); //data to dom
setInterval(function () {
x.a++;
}, 1000);
</script>
</body>
</html>
JSFiddle.
JSFiddle原始代码。
在提供的示例中,对象x的属性由setInterval更新,文本输入的值也会自动更新。如果这还不够,并且事件是你想要的,你可以在上面的输入中添加onchange监听器。如果需要,输入也可以被隐藏。
使用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>
这是不可能的。
但是,这可以使用CustomEvent: https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent/CustomEvent来完成
下面的方法接受一个变量名数组作为输入,并为每个变量添加事件侦听器,并在变量值发生任何更改时触发事件。
该方法使用轮询来检测值的变化。您可以以毫秒为单位增加timeout的值。
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);
}
通过调用方法:
watchVariables(['username', 'userid']);
它将检测变量username和userid的更改。
这不是一个理想的答案,但它所做的是在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已被更改!”:)
是的,现在这是完全可能的!
我知道这是一个旧线程,但现在这种效果是可能使用访问器(getter和setter): https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Working_with_Objects#Defining_getters_and_setters
你可以像这样定义一个对象,其中inner表示字段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;
}
}
然后你可以使用下面的方法注册一个监听器:
x.registerListener(function(val) {
alert("Someone changed the value of x.a to " + val);
});
因此,每当x.a的值发生变化时,监听器函数就会被触发。运行下面的代码行将弹出警告:
x.a = 42;
请看一个例子:https://jsfiddle.net/5o1wf1bn/1/
您还可以使用一个侦听器数组,而不是单个侦听器插槽,但是我想给您一个最简单的示例。