JS에서 특정 변수의 값이 변경 될 때 발생하는 이벤트를 가질 수 있습니까? JQuery가 허용됩니다.
variable
있지만 여기에있는 모든 답변은에 해당합니다 property
. local variable
그래도 변경 사항을 들을 수 있을지 궁금합니다 .
JS에서 특정 변수의 값이 변경 될 때 발생하는 이벤트를 가질 수 있습니까? JQuery가 허용됩니다.
variable
있지만 여기에있는 모든 답변은에 해당합니다 property
. local variable
그래도 변경 사항을 들을 수 있을지 궁금합니다 .
답변:
예, 이제 가능합니다!
나는이 오래된 스레드 알고 있지만 지금이 효과가 접근에게 (getter 및 setter)를 사용하여 가능하다 : 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
.
이 질문에 대한 대부분의 답변은 오래되었거나 비효율적이거나 큰 부풀린 라이브러리를 포함해야합니다.
오늘, 당신은 지금 사용할 수있는 프록시 객체 객체에 대한 변경 모니터 (와 절편)에 있습니다. 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
. 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
사용하면 프록시의 주요 사용 사례 중 하나를 통해 이를 달성 할 수 있습니다 .
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.
이것이 바로 제 요점입니다. 내 경우에는 다른 곳에서 객체를 만들고 다른 코드로 업데이트했습니다 ...이 경우 프록시는 변경 사항이 대상에서 수행되므로 유용하지 않습니다.
아니.
그러나 그것이 정말로 중요하다면, 두 가지 옵션이 있습니다 (첫 번째는 테스트되고 두 번째는 그렇지 않습니다)
먼저 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);
사용 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
있지만 두 개의 인수가 필요하지만 예제의 일부는 value 매개 변수로만 호출되는 함수를 보여줍니다.
오래된 스레드를 가져 와서 죄송하지만 여기에 나와 같은 Eli Grey의 예제가 어떻게 작동하는지 보지 못하는 사람들을위한 약간의 매뉴얼이 있습니다.
var test = new Object();
test.watch("elem", function(prop,oldval,newval){
//Your code
return newval;
});
이것이 누군가를 도울 수 있기를 바랍니다.
으로 누가 쉐퍼의 대답 ( 참고 :이 그의 원래의 게시물을 의미 있지만 요점은 여기에 편집 후 유효 ), 나 또한 가져 오기 한 쌍의 / 당신의 가치를 액세스 할 수있는 설정 방법을 제안합니다.
그러나 나는 약간의 수정을 제안 할 것입니다 (그리고 그것이 내가 게시하는 이유입니다 ...).
이 코드의 문제점 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
눈에 띄지 않게 읽거나 쓸 수있는 방법은 없습니다 .
여전히 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);
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
.
또는 객체와 사용자 getter 및 setter 메소드로 캡슐화 할 수 있습니다.
var
ES6 모듈에서 선언 된 변수의 경우처럼 액세스 할 수 있는 유일한 방법입니다.
초기 질문은 변수가 아니라 변수에 대한 것임을 기억하십시오.)
위의 모든 답변 외에도 forTheWatch.js 라는 작은 lib를 만들었습니다.이 라이브러리 는 자바 스크립트에서 일반 전역 변수의 변경 사항을 포착하고 콜백하는 것과 동일한 방법을 사용합니다.
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의 변경 사항을 감지합니다.
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;
}
}
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로 변경 한 후에는 아무 것도 발생하지 않습니다 .
이제 리스너를 정의 해 봅시다. 우리는 네 청취자가 가능한 : 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를 사용하여 솔루션을 찾는 동안 두 번째로 높은 답변 (사용자 정의 리스너)을 발견했습니다. 솔루션이 작동하는 동안 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
자식 버튼을 클릭 할 때마다 부모에서 업데이트 됩니다. 작업 스택
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]);}
});
}