JavaScript에서 변수 변경 청취
JS에서 특정 변수의 값이 변경 될 때 발생하는 이벤트를 가질 수 있습니까? JQuery가 허용됩니다.
예, 이제 가능합니다!
나는이 오래된 스레드 알고 있지만 지금이 효과가 접근에게 (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/ 예를 참조하십시오.
단일 리스너 슬롯 대신 리스너 배열을 사용할 수도 있지만 가장 간단한 예를 들었습니다.
이 질문에 대한 대부분의 답변은 구식이거나 비효율적이거나 큰 부풀린 라이브러리를 포함해야합니다.
- Object.watch 및 Object.observe 는 더 이상 사용되지 않으며 사용해서는 안됩니다.
- onPropertyChange 는 일부 IE 버전에서만 작동하는 DOM 요소 이벤트 핸들러입니다.
- Object.defineProperty를 사용하면 객체 속성을 변경 불가능하게 만들 수 있으며, 이로 인해 시도 된 변경을 감지 할 수 있지만 모든 변경 사항도 차단됩니다.
- setter 및 getter 정의 는 작동하지만 많은 설정 코드가 필요하며 새 특성을 삭제하거나 작성해야 할 때 제대로 작동하지 않습니다.
오늘, 당신은 지금 사용할 수있는 프록시 객체 객체에 대한 변경 모니터 (와 절편)에 있습니다. 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}}]
아니.
그러나 그것이 정말로 중요하다면, 두 가지 옵션이 있습니다 (첫 번째는 테스트되고 두 번째는 그렇지 않습니다).
먼저 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>
오래된 스레드를 가져 와서 죄송하지만 여기에 나와 같은 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 ()를 사용할 수 있습니다.
AngularJS
(이것은 JQuery
아니지만 이것이 도움이 될 수 있음을 알고 있습니다. [순수 JS는 이론 상으로는 우수합니다]) :
$scope.$watch('data', function(newValue) { ..
여기서 "data"는 범위의 변수 이름입니다.
몇 년 후 조정하는 경우 :
onpropertychange 이벤트와 최신 사양 defineProperty를 사용하는 대부분의 브라우저 (및 IE6 +)에 대한 솔루션을 사용할 수 있습니다. 약간의 문제점은 변수를 dom 객체로 만들어야한다는 것입니다.
세부 사항 :
http://johndyer.name/native-browser-get-set-properties-in-javascript/
찾고있는 기능은 최신 브라우저에서만 사용할 수있는 "defineProperty ()"메소드를 사용하여 얻을 수 있습니다.
더 많은 브라우저 간 지원이 필요한 경우 비슷한 기능을 가진 jQuery 확장을 작성했습니다.
https://github.com/jarederaj/jQueue
변수, 객체 또는 키의 존재에 대한 대기 콜백을 처리하는 작은 jQuery 확장입니다. 백그라운드에서 실행중인 프로세스의 영향을받을 수있는 많은 데이터 포인트에 여러 개의 콜백을 할당 할 수 있습니다. jQueue는 사용자가 지정한 이러한 데이터가 수신 될 때까지 기다렸다가 해당 인수를 사용하여 올바른 콜백을 시작합니다.
직접적이지 않음 : 일종의 "addListener / removeListener"인터페이스 또는 NPAPI 플러그인이있는 페어 getter / setter가 필요합니다 (그러나 이것은 다른 이야기입니다).
//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 메소드로 캡슐화 할 수 있습니다.
직접 가능하지 않습니다.
그러나이 작업은 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의 변경 사항을 감지합니다.
초기 질문은 변수가 아니라 변수에 대한 것임을 기억하십시오.)
위의 모든 답변 외에도 forTheWatch.js 라는 작은 lib를 만들었습니다.이 라이브러리 는 자바 스크립트에서 일반 전역 변수의 변경 사항을 포착하고 콜백하는 동일한 방법을 사용합니다.
JQUERY 변수와 호환되며 OBJECTS를 사용할 필요가 없으며 필요한 경우 여러 변수의 ARRAY를 직접 전달할 수 있습니다.
도움이 될 수 있다면 ... : https://bitbucket.org/esabora/forthewatch
기본적으로 함수를 호출하면됩니다.
watchIt("theVariableToWatch", "varChangedFunctionCallback");
관련이없는 경우 사전에 죄송합니다.
이것은 오래된 스레드이지만 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]);}
});
}
참고 URL : https://stackoverflow.com/questions/1759987/listening-for-variable-changes-in-javascript
'Programming' 카테고리의 다른 글
문자열을 문자 배열로 나누는 방법은 무엇입니까? (0) | 2020.02.20 |
---|---|
cURL로 HTTP 요청 수행 (PROXY 사용) (0) | 2020.02.20 |
Git push를 사용하여 프로젝트 배포 (0) | 2020.02.20 |
빈 세트 리터럴? (0) | 2020.02.20 |
"X-Frame-Options에 의해 금지 된 디스플레이"극복 (0) | 2020.02.20 |