w3schools script que manipular elementos ejemplos definicion aprender javascript javascript-events jquery

que - Escuchando cambios de variables en JavaScript



javascript pdf (16)

Como la respuesta de Luke Schafer ( nota : esto se refiere a su publicación original, pero el punto aquí sigue siendo válido después de la edición), también sugeriría un par de métodos Get / Set para acceder a su valor.

Sin embargo, sugeriría algunas modificaciones (y es por eso que estoy publicando ...).

Un problema con ese código es que el campo a del objeto myobj es directamente accesible, por lo que es posible acceder a él / cambiar su valor sin disparar a los oyentes:

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!

Encapsulacion

Entonces, para garantizar que los oyentes sean realmente llamados, tendríamos que prohibir que el acceso directo al campo a . ¿Cómo hacerlo? Use un cierre !

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 }; })();

Ahora puede usar el mismo método para crear y agregar los oyentes como lo propuso Luke, ¡pero puede estar seguro de que no hay forma posible de leer o escribir en a mensaje que pase desapercibido!

Agregando campos encapsulados programáticamente

Todavía en la pista de Luke, propongo ahora una forma sencilla de agregar campos encapsulados y los respectivos captadores / definidores a los objetos por medio de una simple función de llamada.

Tenga en cuenta que esto solo funcionará correctamente con los tipos de valor . Para que esto funcione con tipos de referencia , se debería implementar algún tipo de copia en profundidad (vea este , por ejemplo).

function addProperty(obj, name, initial) { var field = initial; obj["get_" + name] = function() { return field; } obj["set_" + name] = function(val) { field = val; } }

Esto funciona igual que antes: creamos una variable local en una función y luego creamos un cierre.

¿Cómo usarlo? Sencillo:

var myobj = {}; addProperty(myobj, "total", 0); window.alert(myobj.get_total() == 0); myobj.set_total(10); window.alert(myobj.get_total() == 10);

¿Es posible tener un evento en JS que se activa cuando cambia el valor de una determinada variable? Se acepta jQuery.


La funcionalidad que busca puede lograrse mediante el uso del método "defineProperty ()", que solo está disponible para los navegadores modernos:

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

He escrito una extensión de jQuery que tiene alguna funcionalidad similar si necesitas más compatibilidad con varios navegadores:

https://github.com/jarederaj/jQueue

Una pequeña extensión de jQuery que maneja las devoluciones de llamada a la existencia de una variable, objeto o clave. Puede asignar cualquier número de devoluciones de llamada a cualquier número de puntos de datos que puedan verse afectados por procesos que se ejecutan en segundo plano. jQueue escucha y espera a que estos datos que especifiques aparezcan y luego dispare la devolución de llamada correcta con sus argumentos.


La mayoría de las respuestas a esta pregunta son obsoletas, ineficaces o requieren la inclusión de grandes bibliotecas abultadas:

Hoy en día, ahora puede usar el objeto Proxy para monitorear (e interceptar) los cambios realizados en un objeto. Es un propósito construido para lo que el OP está tratando de hacer. Aquí hay un ejemplo básico:

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

Los únicos inconvenientes del objeto Proxy son:

  1. El objeto Proxy no está disponible en navegadores antiguos (como IE11) y el polyfill no puede replicar completamente la funcionalidad de Proxy .
  2. Los objetos proxy no siempre se comportan como se espera con objetos especiales (por ejemplo, Date ): el objeto Proxy se empareja mejor con Objetos o Arreglos simples.

Si necesita observar los cambios realizados en un objeto anidado , entonces necesita usar una biblioteca especializada como Observable Slim que funciona así:

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}}]


Lamento haber sacado un tema antiguo, pero aquí hay un pequeño manual para quienes (¡como yo!) No ven cómo funciona el ejemplo de Eli Grey:

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

Espero que esto pueda ayudar a alguién


No directamente: necesita un par getter / setter con una interfaz "addListener / removeListener" de algún tipo ... o un plugin NPAPI (pero eso es otra historia).


No es directamente posible.

Sin embargo, esto se puede hacer usando CustomEvent: https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent/CustomEvent

El siguiente método acepta una matriz de nombres de variables como una entrada y agrega un detector de eventos para cada variable y activa el evento para cualquier cambio en el valor de las variables.

El método utiliza el sondeo para detectar el cambio en el valor. Puede aumentar el valor del tiempo de espera en milisegundos.

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); }

Llamando al Método:

watchVariables([''username'', ''userid'']);

Se detectarán los cambios a las variables nombre de usuario y usuario.


No.

Pero, si es realmente tan importante, tienes 2 opciones (la primera es probada, la segunda no):

Primero, use setters y getters, así:

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

entonces puedes hacer algo como:

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)); }

a continuación, establezca el oyente como:

listen_to(myobj, "a", function(oldval, newval) { alert("old : " + oldval + " new : " + newval); }

En segundo lugar, en realidad lo olvidé, lo someteré mientras lo pienso :)

EDIT: Oh, lo recuerdo :) Usted podría poner un reloj en el valor:

Dado myobj arriba, con ''a'' en él:

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


Para aquellos que sintonizan en un par de años más tarde:

Se encuentra disponible una solución para la mayoría de los navegadores (y IE6 +) que utiliza el evento onpropertychange y la especificación más recientePreciedad. El problema es que necesitarás hacer de tu variable un objeto dom.

Todos los detalles:

http://johndyer.name/native-browser-get-set-properties-in-javascript/



Sí, esto es ahora completamente posible!

Sé que este es un hilo antiguo, pero ahora este efecto es posible usando los accesores (getters y setters): https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Working_with_Objects#Defining_getters_and_setters

Puede definir un objeto como este, en el que aInternal representa el campo 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; } }

Luego puedes registrar un oyente usando lo siguiente:

x.registerListener(function(val) { alert("Someone changed the value of x.a to " + val); });

Entonces, cuando algo cambie el valor de xa , la función de escucha se activará. Ejecutando la siguiente línea traerá la ventana emergente de alerta:

x.a = 42;

Vea un ejemplo aquí: https://jsfiddle.net/5o1wf1bn/1/

También puede utilizar una matriz de escuchas en lugar de una única ranura de escucha, pero quería darle el ejemplo más simple posible.


Si está utilizando jQuery {UI} (que todos deberían estar usando :-)), puede usar .change () con un elemento <input /> oculto.


Una solución bastante simple y simple es usar una llamada de función para establecer el valor de la variable global y nunca establecer su valor directamente. De esta manera tienes control total:

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

No hay forma de imponer esto, solo requiere disciplina en la programación ... aunque puede usar grep (o algo similar) para verificar que en ninguna parte su código establece directamente el valor de globalVar .

O podría encapsularlo en un objeto y obtener métodos de obtención y establecimiento de usuarios ... solo un pensamiento.


Uso de 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>

Otro ejemplo

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


AngularJS (Sé que esto no es JQuery , pero eso podría ayudar. [Pure JS solo es bueno en teoría]):

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

donde "datos" es el nombre de su variable en el ámbito.

Hay un enlace a doc.


//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(); } };

o

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

o

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


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]);} }); }