特定の変数の値が変更されたときに発生するイベントをJSで持つことは可能ですか?jQueryが受け入れられます。
variable
ですが、ここでのすべての回答はを参照していproperty
ます。でも、local variable
変化を聞くことができるのかしら。
特定の変数の値が変更されたときに発生するイベントをJSで持つことは可能ですか?jQueryが受け入れられます。
variable
ですが、ここでのすべての回答はを参照していproperty
ます。でも、local variable
変化を聞くことができるのかしら。
回答:
はい、これは完全に可能になりました!
私はこれが古いスレッドであることを知っていますが、今ではこの効果はアクセサ(ゲッターとセッター)を使用して可能です:https : //developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Working_with_Objects#Defining_getters_and_setters
次のようaInternal
にフィールドを表すオブジェクトを定義できます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/
単一のリスナースロットの代わりにリスナーの配列を使用することもできますが、私はできるだけ簡単な例を挙げたいと思いました。
this.aListener(val)
用意することだけです。その後、単に呼び出すのではなく、すべてのリスナー関数をループして、それぞれを渡して呼び出す必要がありますval
。通常、メソッドはのaddListener
代わりに呼び出されますregisterListener
。
この質問への回答のほとんどは、古くなっているか、効果がないか、大規模な肥大化したライブラリを含める必要があります。
現在、Proxyオブジェクトを使用して、オブジェクトに加えられた変更を監視(およびインターセプト)できます。これは、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など)古いブラウザでは利用できませんとポリフィルは完全に複製することはできませんProxy
機能を。Date
) - Proxy
オブジェクトが最高の無地のオブジェクトまたは配列とペアになっています。ネストされたオブジェクトに加えられた変更を監視する必要がある場合は、次のように機能する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}}]
target.hello_world = "test"
)のプロパティがいつ変更されたかを知りたいだけです
you don't actually watch changes on the target object but only on proxy object
-正確ではありません。Proxy
オブジェクトは変更されません-それは、ターゲットのそれ自身のコピーを持っていません。you just want to know when a property change on the target object
-でそれを達成できProxy
ます。これは、プロキシの主な使用例の1つです。
target
、プロキシを介して行う必要があります。ただしproxy.hello_world = "test"
、プロキシを変更しているという意味ではなく、プロキシは変更target
されずに変更されます(設定ハンドラがそうするように構成されている場合)。直接観察できないのがポイントのようですねtarget.hello_world = "test"
。それは本当です。単純な変数の割り当ては、いかなる種類のイベントも発生させません。そのため、この質問への回答で説明されているようなツールを使用する必要があります。
It sounds like your point is that you cannot directly observe target.hello_world = "test". That is true.
それがまさに私の趣旨です。私の場合、別の場所でオブジェクトが作成され、他のコードによって更新されています...この場合、プロキシはターゲットで変更が行われるため、役に立ちません。
番号。
しかし、それが本当にそれほど重要である場合、2つのオプションがあります(最初はテストされ、2番目はテストされません)。
まず、次のようにセッターとゲッターを使用します。
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);
使用Prototype
:https : //developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty
// Console
function print(t) {
var c = document.getElementById('console');
c.innerHTML = c.innerHTML + '<br />' + t;
}
// Demo
var myVar = 123;
Object.defineProperty(this, 'varWatch', {
get: function () { return myVar; },
set: function (v) {
myVar = v;
print('Value changed! New value: ' + v);
}
});
print(varWatch);
varWatch = 456;
print(varWatch);
<pre id="console">
</pre>
// Console
function print(t) {
var c = document.getElementById('console');
c.innerHTML = c.innerHTML + '<br />' + t;
}
// Demo
var varw = (function (context) {
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
print(varWatch);
varWatch = 456;
print(varWatch);
print('---');
varw('otherVarWatch', 123); // Declare with initial value
print(otherVarWatch);
otherVarWatch = 789;
print(otherVarWatch);
<pre id="console">
</pre>
varw
2つの引数が必要ですが、例の一部では、valueパラメーターだけで呼び出される関数を示しています。
古いスレッドを表示して申し訳ありませんが、Eli Greyの例がどのように機能するかがわからない(私のような!)方のための小さなマニュアルがあります。
var test = new Object();
test.watch("elem", function(prop,oldval,newval){
//Your code
return newval;
});
これが誰かを助けることを願っています
ルークシェーファーの回答(注:これは彼のオリジナルのポストを指し、しかし、ここで全体のポイントは、編集後に有効のまま)、私はまた、あなたの値にアクセスするには、Get / Setメソッドのペアをお勧めします。
しかし、私はいくつかの変更を提案します(そしてそれが私が投稿している理由です...)。
このコードの問題a
は、オブジェクトのフィールドにmyobj
直接アクセスできるため、リスナーをトリガーせずにオブジェクトにアクセスしたり、値を変更したりできることです。
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が提案したのと同じメソッドを使用してリスナーを作成および追加できますが、a
気付かれずに読み書きする方法がないため、安心できます。
まだルークの軌道に乗っていますが、カプセル化されたフィールドとそれぞれのゲッター/セッターを単純な関数呼び出しによってオブジェクトに追加する簡単な方法を提案します。
これは値タイプでのみ正しく機能することに注意してください。これが参照型で機能するためには、ある種のディープコピーを実装する必要があります(たとえば、これを参照してください)。
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);
jQuery {UI}(誰もが使用しているはずです:-)を使用している場合は、非表示の<input />要素で.change()を使用できます。
<input/>
要素に変数をアタッチするにはどうすればよいですか?
<input type="hidden" value="" id="thisOne" />
そして、jQuery $("#thisOne").change(function() { do stuff here });
を使用する$("#thisOne").val(myVariableWhichIsNew);
と、ウィルが起動し.change()
ます。
var1 = 'new value';
、コード内の変数を変更する代わりに、この非表示の入力の値を設定し、変数を変更するリスナーを追加します。 $("#val1").on('change', function(){ val1 = this.val(); ... do the stuff that you wanted to do when val1 changed... }); $("#val1").val('new value');
数年後のチューニングのために:
onpropertychangeイベントと新しいスペックのdefinePropertyを使用するほとんどのブラウザー(およびIE6 +)向けのソリューションが利用可能です。わずかな問題は、変数をdomオブジェクトにする必要があることです。
全詳細:
http://johndyer.name/native-browser-get-set-properties-in-javascript/
探している機能は、「defineProperty()」メソッドを使用して実現できます。これは、最新のブラウザでのみ使用できます。
クロスブラウザーのサポートがさらに必要な場合は、いくつかの同様の機能を持つjQuery拡張機能を作成しました。
https://github.com/jarederaj/jQueue
変数、オブジェクト、またはキーの存在へのキューイングコールバックを処理する小さなjQuery拡張。バックグラウンドで実行されているプロセスの影響を受ける可能性のある任意の数のデータポイントに任意の数のコールバックを割り当てることができます。jQueueは、指定されたこれらのデータが存在するようになるまで待機して待機し、引数を使用して正しいコールバックを起動します。
//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();
}
};
または
/* 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);
または
/* 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);
かなり単純で単純な解決策は、関数呼び出しを使用してグローバル変数の値を設定し、その値を直接設定しないことです。このようにして、完全に制御できます。
var globalVar;
function setGlobalVar(value) {
globalVar = value;
console.log("Value of globalVar set to: " + globalVar);
//Whatever else
}
これを強制する方法はありません。プログラミングの規律が必要なだけです... grep
(または同様の方法)を使用して、コードがの値を直接設定していないことを確認できますglobalVar
。
または、オブジェクトとユーザーのゲッターメソッドとセッターメソッドにカプセル化することもできます。
var
ES6モジュールで宣言された変数の場合と同様に、オブジェクトのプロパティではない変数の場合、これが唯一の解決策です。
最初の質問は、オブジェクトではなく変数に関するものだったことを覚えておいてください;)
上記のすべての回答に加えて、私はforTheWatch.jsと呼ばれる小さなlibを作成しました。これは、JavaScriptの通常のグローバル変数の変更をキャッチしてコールバックするのと同じ方法を使用します。
JQUERY変数と互換性があり、OBJECTSを使用する必要はありません。必要に応じて、いくつかの変数のARRAYを直接渡すことができます。
それが役立つ場合...:https :
//bitbucket.org/esabora/forthewatch
基本的には、関数を呼び出す必要があります:
watchIt("theVariableToWatch", "varChangedFunctionCallback");
関連性がない場合は事前に申し訳ありません。
この答えから始めて、私が見つけた最も簡単な方法:
// variable holding your data
const state = {
count: null,
update() {
console.log(`this gets called and your value is ${this.pageNumber}`);
},
get pageNumber() {
return this.count;
},
set pageNumber(pageNumber) {
this.count = pageNumber;
// here you call the code you need
this.update(this.count);
}
};
その後:
state.pageNumber = 0;
// watch the console
state.pageNumber = 15;
// watch the console
私の場合、プロジェクトに含めていたライブラリがを再定義しているかどうかを調べようとしていましたwindow.player
。だから、私のコードの冒頭で、私はちょうどしました:
Object.defineProperty(window, 'player', {
get: () => this._player,
set: v => {
console.log('window.player has been redefined!');
this._player = v;
}
});
直接は不可能です。
ただし、これはCustomEventを使用して行うことができます:https : //developer.mozilla.org/en-US/docs/Web/API/CustomEvent/CustomEvent
以下のメソッドは、変数名の配列を入力として受け入れ、変数ごとにイベントリスナーを追加し、変数の値が変更されるとイベントをトリガーします。
メソッドはポーリングを使用して値の変化を検出します。タイムアウトの値はミリ秒単位で増やすことができます。
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への変更を検出します。
助けを借りてゲッターとセッター、あなたは、このようなAのことを行い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;
}
}
money
変更をリッスンしたいと仮定してMonitoredVariable
、初期資金を使用してのインスタンスを作成してみましょう0
:
const money = new MonitoredVariable(0);
次に、次のコマンドを使用してその値を取得または設定できますmoney.val
。
console.log(money.val); // Get its value
money.val = 2; // Set its value
リスナーを定義していないため、money.val
2 に変更しても特別なことは何も起こりません。
次に、いくつかのリスナーを定義しましょう。我々は、4人のリスナーを用意してくださいbeforeSet
、beforeChange
、afterChange
、afterSet
。を使用money.val = newValue
して変数の値を変更すると、次のことが順次発生します。
次に、変更afterChange
後money.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を参照してください。
これは古いスレッドですが、Angularを使用したソリューションを探しているときに、2番目に高い回答(カスタムリスナー)に出会いました。ソリューションは機能しますが、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);
}
これはn
、子ボタンがクリックされるたびに親で更新されます。ワーキングstackblitz
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]);}
});
}