是否有可能在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>
其他回答
这是一个老线程,但我在使用Angular寻找解决方案时偶然发现了第二高的答案(自定义侦听器)。虽然这个解决方案是可行的,但angular有一个更好的内置方法来解决这个问题,使用@Output和事件发射器。在自定义监听器回答中的例子:
ChildComponent.html
<button (click)="increment(1)">Increment</button>
ChildComponent.ts
import {EventEmitter, Output } from '@angular/core';
@Output() myEmitter: EventEmitter<number> = new EventEmitter<number>();
private myValue: number = 0;
public increment(n: number){
this.myValue += n;
// Send a change event to the emitter
this.myEmitter.emit(this.myValue);
}
ParentComponent.html
<child-component (myEmitter)="monitorChanges($event)"></child-component>
<br/>
<label>{{n}}</label>
ParentComponent.ts
public n: number = 0;
public monitorChanges(n: number){
this.n = n;
console.log(n);
}
现在每次单击子按钮时都会更新非父按钮。工作stackblitz
这个问题是关于变量的,而不是对象属性!因此,我的方法是利用窗口对象及其自定义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
对于那些几年后收听的人来说:
大多数浏览器(和IE6+)都有一个解决方案,它使用onpropertychange事件和更新的规范defineProperty。有一点需要注意的是,您需要将变量设置为dom对象。
详情:
http://johndyer.name/native-browser-get-set-properties-in-javascript/
是的,现在这是完全可能的!
我知道这是一个旧线程,但现在这种效果是可能使用访问器(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/
您还可以使用一个侦听器数组,而不是单个侦听器插槽,但是我想给您一个最简单的示例。
在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。