是否有可能在JS中有一个事件,当某个变量的值发生变化时触发?JQuery被接受。
当前回答
Utils = {
eventRegister_globalVariable : function(variableName,handlers){
eventRegister_JsonVariable(this,variableName,handlers);
},
eventRegister_jsonVariable : function(jsonObj,variableName,handlers){
if(jsonObj.eventRegisteredVariable === undefined) {
jsonObj.eventRegisteredVariable={};//this Object is used for trigger event in javascript variable value changes ku
}
Object.defineProperty(jsonObj, variableName , {
get: function() {
return jsonObj.eventRegisteredVariable[variableName] },
set: function(value) {
jsonObj.eventRegisteredVariable[variableName] = value; handlers(jsonObj.eventRegisteredVariable[variableName]);}
});
}
其他回答
基于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方法将被触发。
正如Luke Schafer的回答(注意:这是指他的原始帖子;但是这里的整个观点在编辑之后仍然有效),我还建议使用一对Get/Set方法来访问你的值。
然而,我想建议一些修改(这就是为什么我在这里发帖……)
这段代码的一个问题是对象myobj的字段A是可以直接访问的,所以可以在不触发侦听器的情况下访问/更改它的值:
var myobj = { a : 5, get_a : function() { return this.a;}, set_a : function(val) { this.a = val; }}
/* add listeners ... */
myobj.a = 10; // no listeners called!
封装
因此,为了保证监听器被实际调用,我们必须禁止直接访问字段a。如何做到这一点?使用闭包!
var myobj = (function() { // Anonymous function to create scope.
var a = 5; // 'a' is local to this function
// and cannot be directly accessed from outside
// this anonymous function's scope
return {
get_a : function() { return a; }, // These functions are closures:
set_a : function(val) { a = val; } // they keep reference to
// something ('a') that was on scope
// where they were defined
};
})();
现在您可以使用Luke建议的相同方法来创建和添加侦听器,但是您可以放心,没有可能的方法来读取或写入一个未被注意到的对象!
以编程方式添加封装的字段
继续Luke的思路,我现在提出一种简单的方法,通过简单的函数调用将封装的字段和各自的getter /setter添加到对象中。
注意,这只适用于值类型。为了与引用类型一起工作,必须实现某种深度复制(例如,请参阅这个)。
function addProperty(obj, name, initial) {
var field = initial;
obj["get_" + name] = function() { return field; }
obj["set_" + name] = function(val) { field = val; }
}
这与之前的工作相同:我们在函数上创建一个局部变量,然后创建一个闭包。
如何使用它?简单:
var myobj = {};
addProperty(myobj, "total", 0);
window.alert(myobj.get_total() == 0);
myobj.set_total(10);
window.alert(myobj.get_total() == 10);
Utils = {
eventRegister_globalVariable : function(variableName,handlers){
eventRegister_JsonVariable(this,variableName,handlers);
},
eventRegister_jsonVariable : function(jsonObj,variableName,handlers){
if(jsonObj.eventRegisteredVariable === undefined) {
jsonObj.eventRegisteredVariable={};//this Object is used for trigger event in javascript variable value changes ku
}
Object.defineProperty(jsonObj, variableName , {
get: function() {
return jsonObj.eventRegisteredVariable[variableName] },
set: function(value) {
jsonObj.eventRegisteredVariable[variableName] = value; handlers(jsonObj.eventRegisteredVariable[variableName]);}
});
}
使用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>
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);