JavaScript에서 변수 변경 청취


462

JS에서 특정 변수의 값이 변경 될 때 발생하는 이벤트를 가질 수 있습니까? JQuery가 허용됩니다.


@ BenjaminGruenbaum 아마 MutableObserver (DOM 용)라고 말하고 싶을 것입니다. 객체는 내가 기억하는 JS 객체에만 해당됩니다.
HellBaby

2
@HellBaby이 질문은 변수가 아닌 DOM에 관한 것입니다.
Benjamin Gruenbaum

9
@BenjaminGruenbaum에 따라 developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/... Object.observe 것은 폐기되었거나 사용되지 않습니다. 동일한 페이지에 대해 권장되는 대체 방법은 Proxy 객체입니다.
stannius

4
에 대한 질문 만 variable있지만 여기에있는 모든 답변은에 해당합니다 property. local variable그래도 변경 사항을 들을 수 있을지 궁금합니다 .
Thariq Nugrohotomo

1
이에 대한 답변이 있습니까? 나는 하나를 선택, 의미
Braian 멜러에게

답변:


100

예, 이제 가능합니다!

나는이 오래된 스레드 알고 있지만 지금이 효과가 접근에게 (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/ 의 예를 참조하십시오.

단일 리스너 슬롯 대신 리스너 배열을 사용할 수도 있지만 가장 간단한 예를 들었습니다.


6
이것은 객체 당 많은 코드입니다. 더 재사용 할 수있는 방법이 있습니까?
Vael Victus

코드는 어디에 있습니까? 새로운 질문을 시작 했습니까?
Akira

객체에 새 속성이 추가되었거나 제거 된시기를 감지하는 방법은 어떻습니까?
Michael

이것은 오래된 대답이지만 배열 값을 푸시하는 대신 배열 값을 설정하는 한 배열 값에 효과적이라고 덧붙이고 싶습니다.
TabsNotSpaces

1
단일 리스너 대신 리스너 배열 만 this.aListener(val)있으면되고, 그냥 호출하는 대신 모든 리스너 함수를 반복하여 각 리스너를 호출해야합니다 val. 일반적으로이 메소드는 addListener대신에 호출 됩니다 registerListener.
Akira

74

이 질문에 대한 대부분의 답변은 오래되었거나 비효율적이거나 큰 부풀린 라이브러리를 포함해야합니다.

  • Object.watchObject.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객체 의 유일한 단점은 다음 과 같습니다.

  1. Proxy객체 (예 : IE11 등) 이전 버전의 브라우저에서 사용할 수 없습니다와 polyfill 수 완전히 복제되지 Proxy기능을 제공합니다.
  2. 프록시 객체는 항상 특수 객체 (예 :)에서 예상대로 작동하지는 않습니다 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}}]

1
또 다른 단점을 추가하겠습니다. 실제로 대상 객체의 변경 사항을 보지 않고 프록시 객체에서만 변경 사항을 볼 수 있습니다. 어떤 경우에는, 당신은 단지 알고 싶어 할 때 대상 객체의 속성 변경 (예 target.hello_world = "test")
크리스티아누

2
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사용하면 프록시의 주요 사용 사례 중 하나를 통해 이를 달성 할 수 있습니다 .
Elliot B.

2
아니요. 타겟을 직접 수정하고 있기 때문입니다. 의 수정 사항을 관찰하려면 target프록시를 통해 수정 해야합니다. 그러나 proxy.hello_world = "test"프록시를 수정하고 프록시가 변경되지 않고 수정된다는 것을 의미하지는 않습니다 target(세트 핸들러가 그렇게 구성한 경우). 요점은 직접 관찰 할 수없는 것 같습니다 target.hello_world = "test". 사실입니다. 일반 변수 할당은 어떤 종류의 이벤트도 발생하지 않습니다. 그렇기 때문에이 질문에 대한 답변에서 설명한 것과 같은 도구를 사용해야합니다.
Elliot B.

2
엘리엇 B. 감사합니다. It sounds like your point is that you cannot directly observe target.hello_world = "test". That is true.이것이 바로 제 요점입니다. 내 경우에는 다른 곳에서 객체를 만들고 다른 코드로 업데이트했습니다 ...이 경우 프록시는 변경 사항이 대상에서 수행되므로 유용하지 않습니다.
Cristiano

1
@Cristiano Elliot이 말하려는 것은 실제 객체 대신 프록시 사용할 수 있다는 것입니다. 즉, 프록시가 객체 인 것처럼 프록시를 전달하고 응용 프로그램의 다른 부분이 프록시와 상호 작용하도록 할 수 있습니다. 프록시의 변경 사항은 실제 개체에 반영됩니다.
Zoltán Matók

33

아니.

그러나 그것이 정말로 중요하다면, 두 가지 옵션이 있습니다 (첫 번째는 테스트되고 두 번째는 그렇지 않습니다)

먼저 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);

8
"보고"는 실제로 변경을 감지하지 않습니다. 이것은 이벤트 기반이 아니며, 곧 전체 앱의 속도가 매우 느려질 것입니다. 이러한 접근 방식은 IMHO가 실제 프로젝트의 일부가되어서는 안됩니다.
Muhammad bin Yusrat

28

사용 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 매개 변수로만 호출되는 함수를 보여줍니다.
Hlawuleka MAS

22

오래된 스레드를 가져 와서 죄송하지만 여기에 나와 같은 Eli Grey의 예제가 어떻게 작동하는지 보지 못하는 사람들을위한 약간의 매뉴얼이 있습니다.

var test = new Object();
test.watch("elem", function(prop,oldval,newval){
    //Your code
    return newval;
});

이것이 누군가를 도울 수 있기를 바랍니다.


9
현재 Chrome 또는 Safari에서 시계가 지원되지 않으며 Firefox 만 지원
Paul McClean

5
mozilla 개발자 네트워크 당 권장하지 않습니다. Object.prototype.watch ()는 테스트 용으로 만 사용되었으며 프로덕션 코드에는 사용해서는 안됩니다. developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
Dennis Bartlett

4
@PaulMcClean이 답변은 Polyfill을 포함하는 Eli Grey의 답변에 대한 답변입니다. gist.github.com/eligrey/384583
Hobbyist

2
Mozilla는 watch를 더 이상 사용하지 않습니다. 이 답변은 오도 될 수 있습니다.
Arnaud

7

으로 누가 쉐퍼의 대답 ( 참고 :이 그의 원래의 게시물을 의미 있지만 요점은 여기에 편집 후 유효 ), 나 또한 가져 오기 한 쌍의 / 당신의 가치를 액세스 할 수있는 설정 방법을 제안합니다.

그러나 나는 약간의 수정을 제안 할 것입니다 (그리고 그것이 내가 게시하는 이유입니다 ...).

이 코드의 문제점 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);

2
캡슐화 +1 그것은 처음 생각했지만, 결국 create_gets_sets 메소드를 추가하는 기능을 원했고, 무차별 적이기 때문에 값을 숨기는 것이 멋지지 않습니다. 내가 게시 한 코드는 대부분의 사람들에게 충분히 혼란 스럽다고 생각합니다. 어쩌면 전화가 필요한 경우 ...
Luke Schafer

6

jQuery {UI} (모든 사람이 :-)를 사용해야하는 경우 숨겨진 <input /> 요소와 함께 .change ()를 사용할 수 있습니다.


7
잘 모르겠습니다. 숨겨진 <input/>요소에 변수를 어떻게 첨부 할 수 있습니까?
Peter Lee

4
척은 jquery와 .change () 이벤트 리스너를 사용하여 입력 값을 설정할 수 있다고 제안합니다. 입력 값을 .val ()로 업데이트하면 .change () 이벤트 콜백이 시작됩니다.
jarederaj

2
<input type="hidden" value="" id="thisOne" />와 jQuery로 $("#thisOne").change(function() { do stuff here });하고 $("#thisOne").val(myVariableWhichIsNew);다음 .change()의지 화재.
khaverim

2
이것은 내 책에서 가장 좋은 솔루션입니다. 간단하고 쉽습니다. 예를 들어 코드에서 변수를 변경하는 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');
Tom Walker

2
나와 같은 문제가있는 사람은 변경 이벤트가 트리거되지 않으면 $ ( "# thisOne"). val (myVariableWhichIsNew) .trigger ( 'change') 시도하십시오. 도움이
되길 바랍니다

6

AngularJS(이것은 JQuery아니지만 이것이 도움이 될 수 있음을 알고 있습니다. [순수 JS는 이론 상으로는 우수합니다]) :

$scope.$watch('data', function(newValue) { ..

여기서 "data"는 범위의 변수 이름입니다.

문서에 대한 링크가 있습니다.


불행히도 변수를 범위에 바인딩하도록 강요합니다
ruX

그것은 $scope.$apply()실행될 때만 해고
iamawebgeek


3

찾고있는 기능은 최신 브라우저에서만 사용할 수있는 "defineProperty ()"메소드를 사용하여 얻을 수 있습니다.

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty

더 많은 브라우저 간 지원이 필요한 경우 비슷한 기능을 가진 jQuery 확장을 작성했습니다.

https://github.com/jarederaj/jQueue

변수, 객체 또는 키의 존재에 대한 대기 콜백을 처리하는 작은 jQuery 확장입니다. 백그라운드에서 실행중인 프로세스의 영향을받을 수있는 여러 데이터 포인트에 여러 개의 콜백을 할당 할 수 있습니다. jQueue는 사용자가 지정한 이러한 데이터가 수신 될 때까지 기다렸다가 해당 인수를 사용하여 올바른 콜백을 시작합니다.


2

직접적이지 않음 : 일종의 "addListener / removeListener"인터페이스 또는 NPAPI 플러그인이있는 페어 getter / setter가 필요합니다 (그러나 이것은 전혀 다른 이야기입니다).


1
//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);

1

다소 간단하고 간단한 해결책은 함수 호출을 사용하여 전역 변수의 값을 설정하고 직접 값을 설정하지 않는 것입니다. 이 방법으로 당신은 완전히 통제 할 수 있습니다 :

var globalVar;

function setGlobalVar(value) {
    globalVar = value;
    console.log("Value of globalVar set to: " + globalVar);
    //Whatever else
}

이를 시행 할 수있는 방법은 없습니다. 프로그래밍 규칙 만 있으면됩니다.하지만 grep코드를 사용하여 코드의 값을 직접 설정하는 곳이 없는지 확인할 수 있습니다 globalVar.

또는 객체와 사용자 getter 및 setter 메소드로 캡슐화 할 수 있습니다.


객체의 속성이 아닌 변수의 경우 varES6 모듈에서 선언 된 변수의 경우처럼 액세스 할 수 있는 유일한 방법입니다.
amn

1

초기 질문은 변수가 아니라 변수에 대한 것임을 기억하십시오.)

위의 모든 답변 외에도 forTheWatch.js 라는 작은 lib를 만들었습니다.이 라이브러리 는 자바 스크립트에서 일반 전역 변수의 변경 사항을 포착하고 콜백하는 것과 동일한 방법을 사용합니다.

JQUERY 변수와 호환되며 OBJECTS를 사용할 필요가 없으며 필요한 경우 여러 변수의 ARRAY를 직접 전달할 수 있습니다.

도움이 될 수 있다면 ... : https://bitbucket.org/esabora/forthewatch
기본적으로 함수를 호출하면됩니다.
watchIt("theVariableToWatch", "varChangedFunctionCallback");

관련이없는 경우 사전에 죄송합니다.


1

이 답변 부터 시작하여 가장 쉬운 방법은 다음과 같습니다.

// 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

1

내 경우에는 프로젝트에 포함하고있는 라이브러리가 내 정의를 재정의하고 있는지 확인하려고했습니다 window.player. 따라서 코드를 시작할 때 방금 다음을 수행했습니다.

Object.defineProperty(window, 'player', {
  get: () => this._player,
  set: v => {
    console.log('window.player has been redefined!');
    this._player = v;
  }
});

0

직접 가능하지 않습니다.

그러나이 작업은 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의 변경 사항을 감지합니다.


0

gettersetter 의 도움으로 이러한 작업을 수행하는 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.val2로 변경 한 후에는 아무 것도 발생하지 않습니다 .

이제 리스너를 정의 해 봅시다. 우리는 네 청취자가 가능한 : beforeSet, beforeChange, afterChange, afterSet. money.val = newValue변수 값을 변경 하는 데 사용하면 다음이 순차적으로 발생합니다 .

  1. money.beforeSet (newValue, oldValue);
  2. money.beforeChange (newValue, oldValue); (값이 변경되지 않으면 생략됩니다)
  3. money.val = newValue;
  4. money.afterChange (newValue, oldValue); (값이 변경되지 않으면 생략됩니다)
  5. money.afterSet (newValue, oldValue);

이제 변경된 afterChange후에 만 트리거되는 리스너를 정의 합니다 (새 값이 이전 값과 동일한 경우에도 트리거 됨).money.valafterSet

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를 참조 하십시오 .


-2

이것은 오래된 스레드이지만 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자식 버튼을 클릭 할 때마다 부모에서 업데이트 됩니다. 작업 스택


-3
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]);}
                    });
            }
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.