是否有可能在JS中有一个事件,当某个变量的值发生变化时触发?JQuery被接受。
当前回答
这个问题最初发布于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}}]
其他回答
//ex:
/*
var x1 = {currentStatus:undefined};
your need is x1.currentStatus value is change trigger event ?
below the code is use try it.
*/
function statusChange(){
console.log("x1.currentStatus_value_is_changed"+x1.eventCurrentStatus);
};
var x1 = {
eventCurrentStatus:undefined,
get currentStatus(){
return this.eventCurrentStatus;
},
set currentStatus(val){
this.eventCurrentStatus=val;
//your function();
}
};
or
/* var x1 = {
eventCurrentStatus:undefined,
currentStatus : {
get : function(){
return Events.eventCurrentStatus
},
set : function(status){
Events.eventCurrentStatus=status;
},
}*/
console.log("eventCurrentStatus = "+ x1.eventCurrentStatus);
x1.currentStatus="create"
console.log("eventCurrentStatus = "+ x1.eventCurrentStatus);
x1.currentStatus="edit"
console.log("eventCurrentStatus = "+ x1.eventCurrentStatus);
console.log("currentStatus = "+ x1.currentStatus);
or
/* global variable ku*/
var jsVarEvents={};
Object.defineProperty(window, "globalvar1", {//no i18n
get: function() { return window.jsVarEvents.globalvarTemp},
set: function(value) { window.window.jsVarEvents.globalvarTemp = value; }
});
console.log(globalvar1);
globalvar1=1;
console.log(globalvar1);
不是直接的:你需要一个“addListener/removeListener”接口的一对getter/setter…或者一个NPAPI插件(但这完全是另一个故事)。
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);
请记住,最初的问题是针对变量的,而不是针对对象的;)
除了上面所有的答案,我创建了一个名为thewatch .js的小库, 在javascript中使用相同的方法来捕捉和回调普通全局变量的变化。
与JQUERY变量兼容,不需要使用object,如果需要,可以直接传递几个变量的ARRAY。
如果有帮助的话……: https://bitbucket.org/esabora/forthewatch基本上你只需要调用这个函数: watchIt(“theVariableToWatch”、“varChangedFunctionCallback”);
如果不相关,先说句抱歉。
我搜索了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监听器。如果需要,输入也可以被隐藏。